Refactoring: use theme
instead of layout
in a lot of places
This commit is contained in:
parent
9427083939
commit
bdc9ba52a6
104 changed files with 445 additions and 449 deletions
|
@ -33,7 +33,7 @@ You can create your own theme at https://mapcomplete.org/studio
|
||||||
What is a good theme?
|
What is a good theme?
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
A **theme** (or _layout_) is a single map showing one or more layers.
|
A **theme** is a single map showing one or more layers.
|
||||||
The layers should work together in such a way that they serve a certain **audience**.
|
The layers should work together in such a way that they serve a certain **audience**.
|
||||||
You should be able to state in a few sentences whom would be the user of such a map, e.g.
|
You should be able to state in a few sentences whom would be the user of such a map, e.g.
|
||||||
|
|
||||||
|
@ -294,12 +294,12 @@ There are three important levels in the JSON file:
|
||||||
|
|
||||||
Every field is documented in the source code itself - you can find them here:
|
Every field is documented in the source code itself - you can find them here:
|
||||||
|
|
||||||
- [The top level `LayoutConfig`](/src/Models/ThemeConfig/Json/LayoutConfigJson.ts)
|
- [The top level `ThemeConfig`](/src/Models/ThemeConfig/Json/ThemeConfigJson.ts)
|
||||||
- [A layer object `LayerConfig`](/src/Models/ThemeConfig/Json/LayerConfigJson.ts)
|
- [A layer object `LayerConfig`](/src/Models/ThemeConfig/Json/LayerConfigJson.ts)
|
||||||
- [The `TagRendering`](/src/Models/ThemeConfig/Json/TagRenderingConfigJson.ts)
|
- [The `TagRendering`](/src/Models/ThemeConfig/Json/TagRenderingConfigJson.ts)
|
||||||
- At last, the exact semantics of tags are documented [here](Tags_format.md)
|
- At last, the exact semantics of tags are documented [here](Tags_format.md)
|
||||||
|
|
||||||
A JSON schema file is available in `Docs/Schemas` - use `LayoutConfig.schema.json` to validate a theme file.
|
A JSON schema file is available in `Docs/Schemas` - use `ThemeConfig.schema.json` to validate a theme file.
|
||||||
|
|
||||||
### MetaTags
|
### MetaTags
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
"minzoom": 18,
|
"minzoom": 18,
|
||||||
"isCounted": false,
|
"isCounted": false,
|
||||||
"calculatedTags": [
|
"calculatedTags": [
|
||||||
"_surface:strict:=feat(get)('_surface')"
|
"_surface:strict:=get(feat)('_surface')"
|
||||||
],
|
],
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
{
|
{
|
||||||
|
@ -224,19 +224,19 @@
|
||||||
"minzoom": 18,
|
"minzoom": 18,
|
||||||
"calculatedTags": [
|
"calculatedTags": [
|
||||||
"_overlaps_with_buildings=overlapWith(feat)('osm_buildings').filter(f => f.feat.properties.id.indexOf('-') < 0)",
|
"_overlaps_with_buildings=overlapWith(feat)('osm_buildings').filter(f => f.feat.properties.id.indexOf('-') < 0)",
|
||||||
"_overlaps_with=feat(get)('_overlaps_with_buildings').find(f => f.overlap > 1 /* square meter */ )",
|
"_overlaps_with=get(feat)('_overlaps_with_buildings').find(f => f.overlap > 1 /* square meter */ )",
|
||||||
"_overlaps_with_properties=feat(get)('_overlaps_with')?.feat?.properties",
|
"_overlaps_with_properties=get(feat)('_overlaps_with')?.feat?.properties",
|
||||||
"_overlap_percentage=Math.round(100 * (feat(get)('_overlaps_with')?.overlap / feat(get)('_overlaps_with_properties')['_surface:strict']))",
|
"_overlap_percentage=Math.round(100 * (get(feat)('_overlaps_with')?.overlap / get(feat)('_overlaps_with_properties')['_surface:strict']))",
|
||||||
"_reverse_overlap_percentage=Math.round(100 * (feat(get)('_overlaps_with')?.overlap / feat(get)('_surface')))",
|
"_reverse_overlap_percentage=Math.round(100 * (get(feat)('_overlaps_with')?.overlap / get(feat)('_surface')))",
|
||||||
"_bag_obj:in_construction=feat.properties.status.startsWith('Bouwvergunning verleend') || feat.properties.status.startsWith('Bouw gestart')",
|
"_bag_obj:in_construction=feat.properties.status.startsWith('Bouwvergunning verleend') || feat.properties.status.startsWith('Bouw gestart')",
|
||||||
"_bag_obj:construction=(feat.properties.gebruiksdoel == 'woonfunctie') ? ((Number(feat.properties.aantal_verblijfsobjecten) == 1) ? 'house' : 'apartments') : 'yes'",
|
"_bag_obj:construction=(feat.properties.gebruiksdoel == 'woonfunctie') ? ((Number(feat.properties.aantal_verblijfsobjecten) == 1) ? 'house' : 'apartments') : 'yes'",
|
||||||
"_bag_obj:building=(feat.properties.status.startsWith('Bouwvergunning verleend') || feat.properties.status.startsWith('Bouw gestart')) ? 'construction' : feat.properties['_bag_obj:construction']",
|
"_bag_obj:building=(feat.properties.status.startsWith('Bouwvergunning verleend') || feat.properties.status.startsWith('Bouw gestart')) ? 'construction' : feat.properties['_bag_obj:construction']",
|
||||||
"_bag_obj:ref:bag=Number(feat.properties.identificatie)",
|
"_bag_obj:ref:bag=Number(feat.properties.identificatie)",
|
||||||
"_bag_obj:source:date=new Date().toISOString().split('T')[0]",
|
"_bag_obj:source:date=new Date().toISOString().split('T')[0]",
|
||||||
"_bag_obj:start_date=feat.properties.bouwjaar",
|
"_bag_obj:start_date=feat.properties.bouwjaar",
|
||||||
"_osm_obj:id=feat(get)('_overlaps_with_properties')?.id",
|
"_osm_obj:id=get(feat)('_overlaps_with_properties')?.id",
|
||||||
"_osm_obj:building=feat(get)('_overlaps_with_properties')?.building",
|
"_osm_obj:building=get(feat)('_overlaps_with_properties')?.building",
|
||||||
"_imported_osm_object_found:=Number(feat.properties.identificatie)==Number(feat(get)('_overlaps_with_properties')['ref:bag'])"
|
"_imported_osm_object_found:=Number(feat.properties.identificatie)==Number(get(feat)('_overlaps_with_properties')['ref:bag'])"
|
||||||
],
|
],
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
{
|
{
|
||||||
|
@ -435,11 +435,11 @@
|
||||||
"_bag_obj:addr:housenumber=`${feat.properties.huisnummer}${feat.properties.huisletter}${(feat.properties.toevoeging != '') ? '-' : ''}${feat.properties.toevoeging}`",
|
"_bag_obj:addr:housenumber=`${feat.properties.huisnummer}${feat.properties.huisletter}${(feat.properties.toevoeging != '') ? '-' : ''}${feat.properties.toevoeging}`",
|
||||||
"_bag_obj:ref:bag=Number(feat.properties.identificatie)",
|
"_bag_obj:ref:bag=Number(feat.properties.identificatie)",
|
||||||
"_bag_obj:source:date=new Date().toISOString().split('T')[0]",
|
"_bag_obj:source:date=new Date().toISOString().split('T')[0]",
|
||||||
"_osm_obj:addr:city:=feat(get)('_closed_osm_addr')['addr:city']",
|
"_osm_obj:addr:city:=get(feat)('_closed_osm_addr')['addr:city']",
|
||||||
"_osm_obj:addr:housenumber:=feat(get)('_closed_osm_addr')['addr:housenumber']",
|
"_osm_obj:addr:housenumber:=get(feat)('_closed_osm_addr')['addr:housenumber']",
|
||||||
"_osm_obj:addr:postcode:=feat(get)('_closed_osm_addr')['addr:postcode']",
|
"_osm_obj:addr:postcode:=get(feat)('_closed_osm_addr')['addr:postcode']",
|
||||||
"_osm_obj:addr:street:=feat(get)('_closed_osm_addr')['addr:street']",
|
"_osm_obj:addr:street:=get(feat)('_closed_osm_addr')['addr:street']",
|
||||||
"_imported_osm_object_found:=(feat.properties.woonplaats==feat(get)('_closed_osm_addr')['addr:city'])&&(feat(get)('_bag_obj:addr:housenumber')==feat(get)('_closed_osm_addr')['addr:housenumber'])&&(feat.properties.postcode==feat(get)('_closed_osm_addr')['addr:postcode'])&&(feat.properties.openbare_ruimte==feat(get)('_closed_osm_addr')['addr:street'])"
|
"_imported_osm_object_found:=(feat.properties.woonplaats==get(feat)('_closed_osm_addr')['addr:city'])&&(get(feat)('_bag_obj:addr:housenumber')==get(feat)('_closed_osm_addr')['addr:housenumber'])&&(feat.properties.postcode==get(feat)('_closed_osm_addr')['addr:postcode'])&&(feat.properties.openbare_ruimte==get(feat)('_closed_osm_addr')['addr:street'])"
|
||||||
],
|
],
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as fs from "fs"
|
||||||
import { existsSync, lstatSync, readdirSync, readFileSync } from "fs"
|
import { existsSync, lstatSync, readdirSync, readFileSync } from "fs"
|
||||||
import { Utils } from "../src/Utils"
|
import { Utils } from "../src/Utils"
|
||||||
import { https } from "follow-redirects"
|
import { https } from "follow-redirects"
|
||||||
import { LayoutConfigJson } from "../src/Models/ThemeConfig/Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../src/Models/ThemeConfig/Json/ThemeConfigJson"
|
||||||
import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson"
|
import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
import xml2js from "xml2js"
|
import xml2js from "xml2js"
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ export default class ScriptUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getThemeFiles(useTranslationPaths = false): {
|
public static getThemeFiles(useTranslationPaths = false): {
|
||||||
parsed: LayoutConfigJson;
|
parsed: ThemeConfigJson;
|
||||||
path: string;
|
path: string;
|
||||||
raw: string
|
raw: string
|
||||||
}[] {
|
}[] {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import QueryParameterDocumentation from "../src/UI/QueryParameterDocumentation"
|
||||||
import ScriptUtils from "./ScriptUtils"
|
import ScriptUtils from "./ScriptUtils"
|
||||||
import Translations from "../src/UI/i18n/Translations"
|
import Translations from "../src/UI/i18n/Translations"
|
||||||
import themeOverview from "../src/assets/generated/theme_overview.json"
|
import themeOverview from "../src/assets/generated/theme_overview.json"
|
||||||
import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig"
|
||||||
import bookcases from "../src/assets/generated/themes/bookcases.json"
|
import bookcases from "../src/assets/generated/themes/bookcases.json"
|
||||||
import fakedom from "fake-dom"
|
import fakedom from "fake-dom"
|
||||||
import unit from "../src/assets/generated/layers/unit.json"
|
import unit from "../src/assets/generated/layers/unit.json"
|
||||||
|
@ -253,7 +253,7 @@ export class GenerateDocs extends Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateHotkeyDocs() {
|
private generateHotkeyDocs() {
|
||||||
new ThemeViewState(new LayoutConfig(<any>bookcases), new Set())
|
new ThemeViewState(new ThemeConfig(<any>bookcases), new Set())
|
||||||
this.WriteMarkdownFile("./Docs/Hotkeys.md", Hotkeys.generateDocumentation(), [
|
this.WriteMarkdownFile("./Docs/Hotkeys.md", Hotkeys.generateDocumentation(), [
|
||||||
"src/UI/Base/Hotkeys.ts",
|
"src/UI/Base/Hotkeys.ts",
|
||||||
])
|
])
|
||||||
|
@ -455,7 +455,7 @@ export class GenerateDocs extends Script {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateForTheme(theme: LayoutConfig): void {
|
private generateForTheme(theme: ThemeConfig): void {
|
||||||
const allLayers = AllSharedLayers.getSharedLayersConfigs()
|
const allLayers = AllSharedLayers.getSharedLayersConfigs()
|
||||||
const layersToShow = theme.layers.filter(
|
const layersToShow = theme.layers.filter(
|
||||||
(l) =>
|
(l) =>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import ScriptUtils from "./ScriptUtils"
|
import ScriptUtils from "./ScriptUtils"
|
||||||
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs"
|
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs"
|
||||||
import licenses from "../src/assets/generated/license_info.json"
|
import licenses from "../src/assets/generated/license_info.json"
|
||||||
import { LayoutConfigJson } from "../src/Models/ThemeConfig/Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../src/Models/ThemeConfig/Json/ThemeConfigJson"
|
||||||
import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson"
|
import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
import Constants from "../src/Models/Constants"
|
import Constants from "../src/Models/Constants"
|
||||||
import {
|
import {
|
||||||
|
@ -29,7 +29,7 @@ import LayerConfig from "../src/Models/ThemeConfig/LayerConfig"
|
||||||
import PointRenderingConfig from "../src/Models/ThemeConfig/PointRenderingConfig"
|
import PointRenderingConfig from "../src/Models/ThemeConfig/PointRenderingConfig"
|
||||||
import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/ConversionContext"
|
import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/ConversionContext"
|
||||||
import { GenerateFavouritesLayer } from "./generateFavouritesLayer"
|
import { GenerateFavouritesLayer } from "./generateFavouritesLayer"
|
||||||
import LayoutConfig, { MinimalLayoutInformation } from "../src/Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig, { MinimalThemeInformation } from "../src/Models/ThemeConfig/ThemeConfig"
|
||||||
import Translations from "../src/UI/i18n/Translations"
|
import Translations from "../src/UI/i18n/Translations"
|
||||||
import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
|
import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
|
||||||
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
||||||
|
@ -148,14 +148,14 @@ class LayerOverviewUtils extends Script {
|
||||||
super("Reviews and generates the compiled themes")
|
super("Reviews and generates the compiled themes")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static publicLayerIdsFrom(themefiles: LayoutConfigJson[]): Set<string> {
|
private static publicLayerIdsFrom(themefiles: ThemeConfigJson[]): Set<string> {
|
||||||
const publicThemes = [].concat(...themefiles.filter((th) => !th.hideFromOverview))
|
const publicThemes = [].concat(...themefiles.filter((th) => !th.hideFromOverview))
|
||||||
|
|
||||||
return new Set([].concat(...publicThemes.map((th) => this.extractLayerIdsFrom(th))))
|
return new Set([].concat(...publicThemes.map((th) => this.extractLayerIdsFrom(th))))
|
||||||
}
|
}
|
||||||
|
|
||||||
private static extractLayerIdsFrom(
|
private static extractLayerIdsFrom(
|
||||||
themeFile: LayoutConfigJson,
|
themeFile: ThemeConfigJson,
|
||||||
includeInlineLayers = true,
|
includeInlineLayers = true,
|
||||||
): string[] {
|
): string[] {
|
||||||
const publicLayerIds: string[] = []
|
const publicLayerIds: string[] = []
|
||||||
|
@ -295,7 +295,7 @@ class LayerOverviewUtils extends Script {
|
||||||
layerKeywords[id] = this.layerKeywords(layer)
|
layerKeywords[id] = this.layerKeywords(layer)
|
||||||
})
|
})
|
||||||
|
|
||||||
const perId = new Map<string, MinimalLayoutInformation>()
|
const perId = new Map<string, MinimalThemeInformation>()
|
||||||
for (const theme of themes) {
|
for (const theme of themes) {
|
||||||
|
|
||||||
const keywords: Record<string, string[]> = {}
|
const keywords: Record<string, string[]> = {}
|
||||||
|
@ -308,7 +308,7 @@ class LayerOverviewUtils extends Script {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = <MinimalLayoutInformation> {
|
const data = <MinimalThemeInformation> {
|
||||||
id: theme.id,
|
id: theme.id,
|
||||||
title: theme.title,
|
title: theme.title,
|
||||||
shortDescription: LayerOverviewUtils.cleanTranslation(theme.shortDescription),
|
shortDescription: LayerOverviewUtils.cleanTranslation(theme.shortDescription),
|
||||||
|
@ -342,7 +342,7 @@ class LayerOverviewUtils extends Script {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
writeTheme(theme: LayoutConfigJson) {
|
writeTheme(theme: ThemeConfigJson) {
|
||||||
if (!existsSync(LayerOverviewUtils.themePath)) {
|
if (!existsSync(LayerOverviewUtils.themePath)) {
|
||||||
mkdirSync(LayerOverviewUtils.themePath)
|
mkdirSync(LayerOverviewUtils.themePath)
|
||||||
}
|
}
|
||||||
|
@ -519,7 +519,7 @@ class LayerOverviewUtils extends Script {
|
||||||
)
|
)
|
||||||
|
|
||||||
new ValidateThemeEnsemble().convertStrict(
|
new ValidateThemeEnsemble().convertStrict(
|
||||||
Array.from(sharedThemes.values()).map((th) => new LayoutConfig(th, true)),
|
Array.from(sharedThemes.values()).map((th) => new ThemeConfig(th, true)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (recompiledThemes.length > 0) {
|
if (recompiledThemes.length > 0) {
|
||||||
|
@ -545,7 +545,7 @@ class LayerOverviewUtils extends Script {
|
||||||
if: "theme=" + th.id,
|
if: "theme=" + th.id,
|
||||||
then: th.icon,
|
then: th.icon,
|
||||||
}))
|
}))
|
||||||
const proto: LayoutConfigJson = JSON.parse(
|
const proto: ThemeConfigJson = JSON.parse(
|
||||||
readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", {
|
readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", {
|
||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
}),
|
}),
|
||||||
|
@ -689,7 +689,7 @@ class LayerOverviewUtils extends Script {
|
||||||
* @param themeFile
|
* @param themeFile
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private extractJavascriptCode(themeFile: LayoutConfigJson) {
|
private extractJavascriptCode(themeFile: ThemeConfigJson) {
|
||||||
const allCode = [
|
const allCode = [
|
||||||
"import {Feature} from 'geojson'",
|
"import {Feature} from 'geojson'",
|
||||||
"import { ExtraFuncType } from \"../../../Logic/ExtraFunctions\";",
|
"import { ExtraFuncType } from \"../../../Logic/ExtraFunctions\";",
|
||||||
|
@ -804,10 +804,10 @@ class LayerOverviewUtils extends Script {
|
||||||
recompiledThemes: string[],
|
recompiledThemes: string[],
|
||||||
forceReload: boolean,
|
forceReload: boolean,
|
||||||
whitelist: Set<string>,
|
whitelist: Set<string>,
|
||||||
): Map<string, LayoutConfigJson> {
|
): Map<string, ThemeConfigJson> {
|
||||||
console.log(" ---------- VALIDATING BUILTIN THEMES ---------")
|
console.log(" ---------- VALIDATING BUILTIN THEMES ---------")
|
||||||
const themeFiles = ScriptUtils.getThemeFiles()
|
const themeFiles = ScriptUtils.getThemeFiles()
|
||||||
const fixed = new Map<string, LayoutConfigJson>()
|
const fixed = new Map<string, ThemeConfigJson>()
|
||||||
|
|
||||||
const publicLayers = LayerOverviewUtils.publicLayerIdsFrom(
|
const publicLayers = LayerOverviewUtils.publicLayerIdsFrom(
|
||||||
themeFiles.map((th) => th.parsed),
|
themeFiles.map((th) => th.parsed),
|
||||||
|
|
|
@ -3,8 +3,8 @@ import Locale from "../src/UI/i18n/Locale"
|
||||||
import Translations from "../src/UI/i18n/Translations"
|
import Translations from "../src/UI/i18n/Translations"
|
||||||
import { Translation } from "../src/UI/i18n/Translation"
|
import { Translation } from "../src/UI/i18n/Translation"
|
||||||
import all_known_layouts from "../src/assets/generated/known_themes.json"
|
import all_known_layouts from "../src/assets/generated/known_themes.json"
|
||||||
import { LayoutConfigJson } from "../src/Models/ThemeConfig/Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../src/Models/ThemeConfig/Json/ThemeConfigJson"
|
||||||
import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig"
|
||||||
import xml2js from "xml2js"
|
import xml2js from "xml2js"
|
||||||
import ScriptUtils from "./ScriptUtils"
|
import ScriptUtils from "./ScriptUtils"
|
||||||
import { Utils } from "../src/Utils"
|
import { Utils } from "../src/Utils"
|
||||||
|
@ -100,7 +100,7 @@ class GenerateLayouts extends Script {
|
||||||
return newname
|
return newname
|
||||||
}
|
}
|
||||||
|
|
||||||
async createSocialImage(layout: LayoutConfig, template: "" | "Wide"): Promise<string> {
|
async createSocialImage(layout: ThemeConfig, template: "" | "Wide"): Promise<string> {
|
||||||
if (!layout.icon.endsWith(".svg")) {
|
if (!layout.icon.endsWith(".svg")) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"Not creating a social image for " +
|
"Not creating a social image for " +
|
||||||
|
@ -160,7 +160,7 @@ class GenerateLayouts extends Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
async createManifest(
|
async createManifest(
|
||||||
layout: LayoutConfig,
|
layout: ThemeConfig,
|
||||||
alreadyWritten: string[]
|
alreadyWritten: string[]
|
||||||
): Promise<{
|
): Promise<{
|
||||||
manifest: any
|
manifest: any
|
||||||
|
@ -319,8 +319,8 @@ class GenerateLayouts extends Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateCsp(
|
async generateCsp(
|
||||||
layout: LayoutConfig,
|
layout: ThemeConfig,
|
||||||
layoutJson: LayoutConfigJson,
|
layoutJson: ThemeConfigJson,
|
||||||
options: {
|
options: {
|
||||||
scriptSrcs: string[]
|
scriptSrcs: string[]
|
||||||
}
|
}
|
||||||
|
@ -441,8 +441,8 @@ class GenerateLayouts extends Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
async createLandingPage(
|
async createLandingPage(
|
||||||
layout: LayoutConfig,
|
layout: ThemeConfig,
|
||||||
layoutJson: LayoutConfigJson,
|
layoutJson: ThemeConfigJson,
|
||||||
whiteIcons,
|
whiteIcons,
|
||||||
alreadyWritten
|
alreadyWritten
|
||||||
) {
|
) {
|
||||||
|
@ -456,7 +456,7 @@ class GenerateLayouts extends Script {
|
||||||
.replace(/"/g, '\\"')
|
.replace(/"/g, '\\"')
|
||||||
let ogImage = layout.socialImage
|
let ogImage = layout.socialImage
|
||||||
let twitterImage = ogImage
|
let twitterImage = ogImage
|
||||||
if (ogImage === LayoutConfig.defaultSocialImage && layout.official) {
|
if (ogImage === ThemeConfig.defaultSocialImage && layout.official) {
|
||||||
try {
|
try {
|
||||||
ogImage = (await this.createSocialImage(layout, "")) ?? layout.socialImage
|
ogImage = (await this.createSocialImage(layout, "")) ?? layout.socialImage
|
||||||
twitterImage = (await this.createSocialImage(layout, "Wide")) ?? layout.socialImage
|
twitterImage = (await this.createSocialImage(layout, "Wide")) ?? layout.socialImage
|
||||||
|
@ -573,7 +573,7 @@ class GenerateLayouts extends Script {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async createIndexFor(theme: LayoutConfig) {
|
async createIndexFor(theme: ThemeConfig) {
|
||||||
const filename = "index_" + theme.id + ".ts"
|
const filename = "index_" + theme.id + ".ts"
|
||||||
|
|
||||||
const imports = [
|
const imports = [
|
||||||
|
@ -628,18 +628,18 @@ class GenerateLayouts extends Script {
|
||||||
"theme",
|
"theme",
|
||||||
]
|
]
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const all: LayoutConfigJson[] = all_known_layouts.themes
|
const all: ThemeConfigJson[] = all_known_layouts.themes
|
||||||
const args = process.argv
|
const args = process.argv
|
||||||
const theme = args[2]
|
const theme = args[2]
|
||||||
if (theme !== undefined) {
|
if (theme !== undefined) {
|
||||||
console.warn("Only generating layout " + theme)
|
console.warn("Only generating layout " + theme)
|
||||||
}
|
}
|
||||||
for (const i in all) {
|
for (const i in all) {
|
||||||
const layoutConfigJson: LayoutConfigJson = all[i]
|
const layoutConfigJson: ThemeConfigJson = all[i]
|
||||||
if (theme !== undefined && layoutConfigJson.id !== theme) {
|
if (theme !== undefined && layoutConfigJson.id !== theme) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const layout = new LayoutConfig(layoutConfigJson, true)
|
const layout = new ThemeConfig(layoutConfigJson, true)
|
||||||
const layoutName = layout.id
|
const layoutName = layout.id
|
||||||
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {
|
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {
|
||||||
console.log(`Skipping a layout with name ${layoutName}, it is on the blacklist`)
|
console.log(`Skipping a layout with name ${layoutName}, it is on the blacklist`)
|
||||||
|
@ -668,7 +668,7 @@ class GenerateLayouts extends Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { manifest } = await this.createManifest(
|
const { manifest } = await this.createManifest(
|
||||||
new LayoutConfig({
|
new ThemeConfig({
|
||||||
icon: "./assets/svg/mapcomplete_logo.svg",
|
icon: "./assets/svg/mapcomplete_logo.svg",
|
||||||
id: "index",
|
id: "index",
|
||||||
layers: [],
|
layers: [],
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts"
|
||||||
import Locale from "../src/UI/i18n/Locale"
|
import Locale from "../src/UI/i18n/Locale"
|
||||||
import { Translation } from "../src/UI/i18n/Translation"
|
import { Translation } from "../src/UI/i18n/Translation"
|
||||||
import { readFileSync, writeFileSync } from "fs"
|
import { readFileSync, writeFileSync } from "fs"
|
||||||
import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig"
|
||||||
import LayerConfig from "../src/Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../src/Models/ThemeConfig/LayerConfig"
|
||||||
import { Utils } from "../src/Utils"
|
import { Utils } from "../src/Utils"
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ function generateTagOverview(
|
||||||
return overview
|
return overview
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateLayerUsage(layer: LayerConfig, layout: LayoutConfig): any[] {
|
function generateLayerUsage(layer: LayerConfig, layout: ThemeConfig): any[] {
|
||||||
if (layer.name === undefined) {
|
if (layer.name === undefined) {
|
||||||
return [] // Probably a duplicate or irrelevant layer
|
return [] // Probably a duplicate or irrelevant layer
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ function generateLayerUsage(layer: LayerConfig, layout: LayoutConfig): any[] {
|
||||||
* Generates the JSON-object representing the theme for inclusion on taginfo
|
* Generates the JSON-object representing the theme for inclusion on taginfo
|
||||||
* @param layout
|
* @param layout
|
||||||
*/
|
*/
|
||||||
function generateTagInfoEntry(layout: LayoutConfig): any {
|
function generateTagInfoEntry(layout: ThemeConfig): any {
|
||||||
const usedTags = []
|
const usedTags = []
|
||||||
for (const layer of layout.layers) {
|
for (const layer of layout.layers) {
|
||||||
if (layer.source === null) {
|
if (layer.source === null) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ type ErrorMessage = {
|
||||||
message: {
|
message: {
|
||||||
stacktrace: string
|
stacktrace: string
|
||||||
message: string
|
message: string
|
||||||
layout: string
|
theme: string
|
||||||
version: string
|
version: string
|
||||||
language: string
|
language: string
|
||||||
username: string
|
username: string
|
||||||
|
@ -40,7 +40,7 @@ class HandleErrors extends Script {
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
parsed.message.username,
|
parsed.message.username,
|
||||||
parsed.message.layout,
|
parsed.message.theme,
|
||||||
parsed.message.message,
|
parsed.message.message,
|
||||||
parsed.date
|
parsed.date
|
||||||
)
|
)
|
||||||
|
@ -82,7 +82,7 @@ class HandleErrors extends Script {
|
||||||
} = changesObj.CreateChangesetObjects(toUpload, objects, true)
|
} = changesObj.CreateChangesetObjects(toUpload, objects, true)
|
||||||
|
|
||||||
const changeset = Changes.buildChangesetXML("", changes)
|
const changeset = Changes.buildChangesetXML("", changes)
|
||||||
const path = "error_changeset_" + parsed.index + "_" + e.layout + "_" + e.username + ".osc"
|
const path = "error_changeset_" + parsed.index + "_" + e.theme + "_" + e.username + ".osc"
|
||||||
if (
|
if (
|
||||||
changeset ===
|
changeset ===
|
||||||
`<osmChange version='0.6' generator='Mapcomplete ${Constants.vNumber}'></osmChange>`
|
`<osmChange version='0.6' generator='Mapcomplete ${Constants.vNumber}'></osmChange>`
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import known_themes from "../assets/generated/known_themes.json"
|
import known_themes from "../assets/generated/known_themes.json"
|
||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||||
import favourite from "../assets/generated/layers/favourite.json"
|
import favourite from "../assets/generated/layers/favourite.json"
|
||||||
import { LayoutConfigJson } from "../Models/ThemeConfig/Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../Models/ThemeConfig/Json/ThemeConfigJson"
|
||||||
import { AllSharedLayers } from "./AllSharedLayers"
|
import { AllSharedLayers } from "./AllSharedLayers"
|
||||||
import Constants from "../Models/Constants"
|
import Constants from "../Models/Constants"
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ import Constants from "../Models/Constants"
|
||||||
* Somewhat of a dictionary, which lazily parses needed themes
|
* Somewhat of a dictionary, which lazily parses needed themes
|
||||||
*/
|
*/
|
||||||
export class AllKnownLayoutsLazy {
|
export class AllKnownLayoutsLazy {
|
||||||
private readonly raw: Map<string, LayoutConfigJson> = new Map()
|
private readonly raw: Map<string, ThemeConfigJson> = new Map()
|
||||||
private readonly dict: Map<string, LayoutConfig> = new Map()
|
private readonly dict: Map<string, ThemeConfig> = new Map()
|
||||||
|
|
||||||
constructor(includeFavouriteLayer = true) {
|
constructor(includeFavouriteLayer = true) {
|
||||||
for (const layoutConfigJson of known_themes["themes"]) {
|
for (const layoutConfigJson of known_themes["themes"]) {
|
||||||
|
@ -32,7 +32,7 @@ export class AllKnownLayoutsLazy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConfig(key: string): LayoutConfigJson {
|
public getConfig(key: string): ThemeConfigJson {
|
||||||
return this.raw.get(key)
|
return this.raw.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,13 +40,13 @@ export class AllKnownLayoutsLazy {
|
||||||
return this.raw.size
|
return this.raw.size
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(key: string): LayoutConfig {
|
public get(key: string): ThemeConfig {
|
||||||
const cached = this.dict.get(key)
|
const cached = this.dict.get(key)
|
||||||
if (cached !== undefined) {
|
if (cached !== undefined) {
|
||||||
return cached
|
return cached
|
||||||
}
|
}
|
||||||
|
|
||||||
const layout = new LayoutConfig(this.getConfig(key))
|
const layout = new ThemeConfig(this.getConfig(key))
|
||||||
this.dict.set(key, layout)
|
this.dict.set(key, layout)
|
||||||
return layout
|
return layout
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../UIEventSource"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||||
import { QueryParameters } from "../Web/QueryParameters"
|
import { QueryParameters } from "../Web/QueryParameters"
|
||||||
import Hash from "../Web/Hash"
|
import Hash from "../Web/Hash"
|
||||||
|
@ -25,7 +25,7 @@ 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: LayoutConfig, geolocationState: GeoLocationState) {
|
constructor(layoutToUse: ThemeConfig, geolocationState: GeoLocationState) {
|
||||||
function localStorageSynced(
|
function localStorageSynced(
|
||||||
key: string,
|
key: string,
|
||||||
deflt: number,
|
deflt: number,
|
||||||
|
|
|
@ -14,7 +14,7 @@ export default class NoElementsInViewDetector {
|
||||||
constructor(themeViewState: ThemeViewState) {
|
constructor(themeViewState: ThemeViewState) {
|
||||||
const state = themeViewState
|
const state = themeViewState
|
||||||
const minZoom = Math.min(
|
const minZoom = Math.min(
|
||||||
...themeViewState.layout.layers
|
...themeViewState.theme.layers
|
||||||
.filter((l) => Constants.priviliged_layers.indexOf(<any>l.id) < 0)
|
.filter((l) => Constants.priviliged_layers.indexOf(<any>l.id) < 0)
|
||||||
.map((l) => l.minzoom)
|
.map((l) => l.minzoom)
|
||||||
)
|
)
|
||||||
|
@ -43,7 +43,7 @@ export default class NoElementsInViewDetector {
|
||||||
// Nope, no data loaded
|
// Nope, no data loaded
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const layer = themeViewState.layout.getLayer(layerName)
|
const layer = themeViewState.theme.getLayer(layerName)
|
||||||
if (mapProperties.zoom.data < layer.minzoom) {
|
if (mapProperties.zoom.data < layer.minzoom) {
|
||||||
minzoomWithData = Math.min(layer.minzoom)
|
minzoomWithData = Math.min(layer.minzoom)
|
||||||
continue
|
continue
|
||||||
|
@ -67,7 +67,7 @@ export default class NoElementsInViewDetector {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const layer = themeViewState.layout.getLayer(layerName)
|
const layer = themeViewState.theme.getLayer(layerName)
|
||||||
if (mapProperties.zoom.data < layer.minzoom) {
|
if (mapProperties.zoom.data < layer.minzoom) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ export default class SelectedElementTagsUpdater {
|
||||||
|
|
||||||
public static applyUpdate(latestTags: OsmTags, id: string, state: SpecialVisualizationState) {
|
public static applyUpdate(latestTags: OsmTags, id: string, state: SpecialVisualizationState) {
|
||||||
try {
|
try {
|
||||||
const leftRightSensitive = state.layout.isLeftRightSensitive()
|
const leftRightSensitive = state.theme.isLeftRightSensitive()
|
||||||
|
|
||||||
if (leftRightSensitive) {
|
if (leftRightSensitive) {
|
||||||
SimpleMetaTagger.removeBothTagging(latestTags)
|
SimpleMetaTagger.removeBothTagging(latestTags)
|
||||||
|
@ -111,7 +111,7 @@ export default class SelectedElementTagsUpdater {
|
||||||
}
|
}
|
||||||
private invalidateCache(s: Feature) {
|
private invalidateCache(s: Feature) {
|
||||||
const state = this.state
|
const state = this.state
|
||||||
const wasPartOfLayer = state.layout.getMatchingLayer(s.properties)
|
const wasPartOfLayer = state.theme.getMatchingLayer(s.properties)
|
||||||
state.toCacheSavers?.get(wasPartOfLayer.id)?.invalidateCacheAround(BBox.get(s))
|
state.toCacheSavers?.get(wasPartOfLayer.id)?.invalidateCacheAround(BBox.get(s))
|
||||||
}
|
}
|
||||||
private installCallback() {
|
private installCallback() {
|
||||||
|
|
|
@ -12,11 +12,11 @@ export default class TitleHandler {
|
||||||
const currentTitle: Store<string> = selectedElement.map(
|
const currentTitle: Store<string> = selectedElement.map(
|
||||||
(selected) => {
|
(selected) => {
|
||||||
const lng = Locale.language.data
|
const lng = Locale.language.data
|
||||||
const defaultTitle = state.layout?.title?.textFor(lng) ?? "MapComplete"
|
const defaultTitle = state.theme?.title?.textFor(lng) ?? "MapComplete"
|
||||||
if (selected === undefined) {
|
if (selected === undefined) {
|
||||||
return defaultTitle
|
return defaultTitle
|
||||||
}
|
}
|
||||||
const layer = state.layout.getMatchingLayer(selected.properties)
|
const layer = state.theme.getMatchingLayer(selected.properties)
|
||||||
if (layer === undefined) {
|
if (layer === undefined) {
|
||||||
return defaultTitle
|
return defaultTitle
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||||
import { QueryParameters } from "./Web/QueryParameters"
|
import { QueryParameters } from "./Web/QueryParameters"
|
||||||
import { AllKnownLayouts } from "../Customizations/AllKnownLayouts"
|
import { AllKnownLayouts } from "../Customizations/AllKnownLayouts"
|
||||||
import { FixedUiElement } from "../UI/Base/FixedUiElement"
|
import { FixedUiElement } from "../UI/Base/FixedUiElement"
|
||||||
|
@ -19,10 +19,10 @@ import { DesugaringContext } from "../Models/ThemeConfig/Conversion/Conversion"
|
||||||
import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson"
|
import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||||
import Hash from "./Web/Hash"
|
import Hash from "./Web/Hash"
|
||||||
import { QuestionableTagRenderingConfigJson } from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
import { QuestionableTagRenderingConfigJson } from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
||||||
import { LayoutConfigJson } from "../Models/ThemeConfig/Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../Models/ThemeConfig/Json/ThemeConfigJson"
|
||||||
import { ValidateThemeAndLayers } from "../Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
import { ValidateThemeAndLayers } from "../Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
||||||
|
|
||||||
export default class DetermineLayout {
|
export default class DetermineTheme {
|
||||||
private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path))
|
private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path))
|
||||||
private static readonly loadCustomThemeParam = QueryParameters.GetQueryParameter(
|
private static readonly loadCustomThemeParam = QueryParameters.GetQueryParameter(
|
||||||
"userlayout",
|
"userlayout",
|
||||||
|
@ -31,7 +31,7 @@ export default class DetermineLayout {
|
||||||
)
|
)
|
||||||
|
|
||||||
public static getCustomDefinition(): string {
|
public static getCustomDefinition(): string {
|
||||||
const layoutFromBase64 = decodeURIComponent(DetermineLayout.loadCustomThemeParam.data)
|
const layoutFromBase64 = decodeURIComponent(DetermineTheme.loadCustomThemeParam.data)
|
||||||
|
|
||||||
if (layoutFromBase64.startsWith("http")) {
|
if (layoutFromBase64.startsWith("http")) {
|
||||||
return layoutFromBase64
|
return layoutFromBase64
|
||||||
|
@ -53,8 +53,8 @@ export default class DetermineLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async expandRemoteLayers(
|
private static async expandRemoteLayers(
|
||||||
layoutConfig: LayoutConfigJson
|
layoutConfig: ThemeConfigJson
|
||||||
): Promise<LayoutConfigJson> {
|
): Promise<ThemeConfigJson> {
|
||||||
if (!layoutConfig.layers) {
|
if (!layoutConfig.layers) {
|
||||||
// This is probably a layer in 'layer-only-mode'
|
// This is probably a layer in 'layer-only-mode'
|
||||||
return layoutConfig
|
return layoutConfig
|
||||||
|
@ -79,16 +79,16 @@ export default class DetermineLayout {
|
||||||
/**
|
/**
|
||||||
* Gets the correct layout for this website
|
* Gets the correct layout for this website
|
||||||
*/
|
*/
|
||||||
public static async GetLayout(): Promise<LayoutConfig | undefined> {
|
public static async getTheme(): Promise<ThemeConfig | undefined> {
|
||||||
const layoutFromBase64 = decodeURIComponent(DetermineLayout.loadCustomThemeParam.data)
|
const layoutFromBase64 = decodeURIComponent(DetermineTheme.loadCustomThemeParam.data)
|
||||||
|
|
||||||
if (layoutFromBase64.startsWith("http")) {
|
if (layoutFromBase64.startsWith("http")) {
|
||||||
return await DetermineLayout.LoadRemoteTheme(layoutFromBase64)
|
return await DetermineTheme.LoadRemoteTheme(layoutFromBase64)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layoutFromBase64 !== "false") {
|
if (layoutFromBase64 !== "false") {
|
||||||
// We have to load something from the hash (or from disk)
|
// We have to load something from the hash (or from disk)
|
||||||
return await DetermineLayout.LoadLayoutFromHash(DetermineLayout.loadCustomThemeParam)
|
return await DetermineTheme.LoadLayoutFromHash(DetermineTheme.loadCustomThemeParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
let layoutId: string = undefined
|
let layoutId: string = undefined
|
||||||
|
@ -127,7 +127,7 @@ export default class DetermineLayout {
|
||||||
|
|
||||||
public static async LoadLayoutFromHash(
|
public static async LoadLayoutFromHash(
|
||||||
userLayoutParam: UIEventSource<string>
|
userLayoutParam: UIEventSource<string>
|
||||||
): Promise<LayoutConfig | null> {
|
): Promise<ThemeConfig | null> {
|
||||||
let hash = location.hash.substr(1)
|
let hash = location.hash.substr(1)
|
||||||
let json: any
|
let json: any
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ export default class DetermineLayout {
|
||||||
|
|
||||||
json = await this.expandRemoteLayers(json)
|
json = await this.expandRemoteLayers(json)
|
||||||
|
|
||||||
const layoutToUse = DetermineLayout.prepCustomTheme(json)
|
const layoutToUse = DetermineTheme.prepCustomTheme(json)
|
||||||
userLayoutParam.setData(layoutToUse.id)
|
userLayoutParam.setData(layoutToUse.id)
|
||||||
return layoutToUse
|
return layoutToUse
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ export default class DetermineLayout {
|
||||||
const dict = new Map<string, QuestionableTagRenderingConfigJson>()
|
const dict = new Map<string, QuestionableTagRenderingConfigJson>()
|
||||||
|
|
||||||
for (const tagRendering of questions.tagRenderings) {
|
for (const tagRendering of questions.tagRenderings) {
|
||||||
dict.set(tagRendering.id, tagRendering)
|
dict.set(tagRendering.id, <QuestionableTagRenderingConfigJson> tagRendering)
|
||||||
}
|
}
|
||||||
|
|
||||||
return dict
|
return dict
|
||||||
|
@ -176,7 +176,7 @@ export default class DetermineLayout {
|
||||||
return questions.tagRenderings.map((tr) => tr.id)
|
return questions.tagRenderings.map((tr) => tr.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static prepCustomTheme(json: any, sourceUrl?: string, forceId?: string): LayoutConfig {
|
private static prepCustomTheme(json: any, sourceUrl?: string, forceId?: string): ThemeConfig {
|
||||||
if (json.layers === undefined && json.tagRenderings !== undefined) {
|
if (json.layers === undefined && json.tagRenderings !== undefined) {
|
||||||
// We got fed a layer instead of a theme
|
// We got fed a layer instead of a theme
|
||||||
const layerConfig = <LayerConfigJson>json
|
const layerConfig = <LayerConfigJson>json
|
||||||
|
@ -224,15 +224,15 @@ export default class DetermineLayout {
|
||||||
knownLayersDict.set(layer.id, <LayerConfigJson>layer)
|
knownLayersDict.set(layer.id, <LayerConfigJson>layer)
|
||||||
}
|
}
|
||||||
const convertState: DesugaringContext = {
|
const convertState: DesugaringContext = {
|
||||||
tagRenderings: DetermineLayout.getSharedTagRenderings(),
|
tagRenderings: DetermineTheme.getSharedTagRenderings(),
|
||||||
tagRenderingOrder: DetermineLayout.getSharedTagRenderingOrder(),
|
tagRenderingOrder: DetermineTheme.getSharedTagRenderingOrder(),
|
||||||
sharedLayers: knownLayersDict,
|
sharedLayers: knownLayersDict,
|
||||||
publicLayers: new Set<string>(),
|
publicLayers: new Set<string>(),
|
||||||
}
|
}
|
||||||
json = new FixLegacyTheme().convertStrict(json)
|
json = new FixLegacyTheme().convertStrict(json)
|
||||||
const raw = json
|
const raw = json
|
||||||
|
|
||||||
json = new FixImages(DetermineLayout._knownImages).convertStrict(json)
|
json = new FixImages(DetermineTheme._knownImages).convertStrict(json)
|
||||||
json.enableNoteImports = json.enableNoteImports ?? false
|
json.enableNoteImports = json.enableNoteImports ?? false
|
||||||
json = new PrepareTheme(convertState).convertStrict(json)
|
json = new PrepareTheme(convertState).convertStrict(json)
|
||||||
console.log("The layoutconfig is ", json)
|
console.log("The layoutconfig is ", json)
|
||||||
|
@ -249,20 +249,20 @@ export default class DetermineLayout {
|
||||||
false
|
false
|
||||||
).convertStrict(json)
|
).convertStrict(json)
|
||||||
}
|
}
|
||||||
return new LayoutConfig(json, false, {
|
return new ThemeConfig(json, false, {
|
||||||
definitionRaw: JSON.stringify(raw, null, " "),
|
definitionRaw: JSON.stringify(raw, null, " "),
|
||||||
definedAtUrl: sourceUrl,
|
definedAtUrl: sourceUrl,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async LoadRemoteTheme(link: string): Promise<LayoutConfig | null> {
|
private static async LoadRemoteTheme(link: string): Promise<ThemeConfig | null> {
|
||||||
console.log("Downloading map theme from ", link)
|
console.log("Downloading map theme from ", link)
|
||||||
|
|
||||||
new FixedUiElement(`Downloading the theme from the <a href="${link}">link</a>...`).AttachTo(
|
new FixedUiElement(`Downloading the theme from the <a href="${link}">link</a>...`).AttachTo(
|
||||||
"maindiv"
|
"maindiv"
|
||||||
)
|
)
|
||||||
|
|
||||||
let parsed = <LayoutConfigJson>await Utils.downloadJson(link)
|
let parsed = <ThemeConfigJson>await Utils.downloadJson(link)
|
||||||
let forcedId = parsed.id
|
let forcedId = parsed.id
|
||||||
const url = new URL(link)
|
const url = new URL(link)
|
||||||
if (!(url.hostname === "localhost" || url.hostname === "127.0.0.1")) {
|
if (!(url.hostname === "localhost" || url.hostname === "127.0.0.1")) {
|
||||||
|
@ -270,6 +270,6 @@ export default class DetermineLayout {
|
||||||
}
|
}
|
||||||
console.log("Loaded remote link:", link)
|
console.log("Loaded remote link:", link)
|
||||||
parsed = await this.expandRemoteLayers(parsed)
|
parsed = await this.expandRemoteLayers(parsed)
|
||||||
return DetermineLayout.prepCustomTheme(parsed, link, forcedId)
|
return DetermineTheme.prepCustomTheme(parsed, link, forcedId)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -49,7 +49,7 @@ export default class FavouritesFeatureSource extends StaticFeatureSource {
|
||||||
|
|
||||||
const featuresWithoutAlreadyPresent = features.map((features) =>
|
const featuresWithoutAlreadyPresent = features.map((features) =>
|
||||||
features.filter(
|
features.filter(
|
||||||
(feat) => !state.layout.layers.some((l) => l.id === feat.properties._orig_layer)
|
(feat) => !state.theme.layers.some((l) => l.id === feat.properties._orig_layer)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
|
||||||
import { Feature, Point } from "geojson"
|
import { Feature, Point } from "geojson"
|
||||||
import { TagUtils } from "../../Tags/TagUtils"
|
import { TagUtils } from "../../Tags/TagUtils"
|
||||||
|
@ -22,7 +22,7 @@ export class LastClickFeatureSource implements FeatureSource {
|
||||||
private _usermode: UIEventSource<string>
|
private _usermode: UIEventSource<string>
|
||||||
private _enabledAddMorePoints: UIEventSource<boolean>
|
private _enabledAddMorePoints: UIEventSource<boolean>
|
||||||
constructor(
|
constructor(
|
||||||
layout: LayoutConfig,
|
layout: ThemeConfig,
|
||||||
clickSource: Store<{ lon: number; lat: number; mode: "left" | "right" | "middle" }>,
|
clickSource: Store<{ lon: number; lat: number; mode: "left" | "right" | "middle" }>,
|
||||||
usermode?: UIEventSource<string>,
|
usermode?: UIEventSource<string>,
|
||||||
enabledAddMorePoints?: UIEventSource<boolean>
|
enabledAddMorePoints?: UIEventSource<boolean>
|
||||||
|
|
|
@ -18,7 +18,7 @@ import FeatureSourceMerger from "./FeatureSourceMerger"
|
||||||
*
|
*
|
||||||
* Note that special layers (with `source=null` will be ignored)
|
* Note that special layers (with `source=null` will be ignored)
|
||||||
*/
|
*/
|
||||||
export default class LayoutSource extends FeatureSourceMerger {
|
export default class ThemeSource extends FeatureSourceMerger {
|
||||||
/**
|
/**
|
||||||
* Indicates if a data source is loading something
|
* Indicates if a data source is loading something
|
||||||
*/
|
*/
|
||||||
|
@ -51,7 +51,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
||||||
const src = new LocalStorageFeatureSource(
|
const src = new LocalStorageFeatureSource(
|
||||||
backend,
|
backend,
|
||||||
layer,
|
layer,
|
||||||
LayoutSource.fromCacheZoomLevel,
|
ThemeSource.fromCacheZoomLevel,
|
||||||
mapProperties,
|
mapProperties,
|
||||||
{
|
{
|
||||||
isActive: isDisplayed(layer.id),
|
isActive: isDisplayed(layer.id),
|
||||||
|
@ -63,13 +63,13 @@ export default class LayoutSource extends FeatureSourceMerger {
|
||||||
}
|
}
|
||||||
const mvtSources: UpdatableFeatureSource[] = osmLayers
|
const mvtSources: UpdatableFeatureSource[] = osmLayers
|
||||||
.filter((f) => mvtAvailableLayers.has(f.id))
|
.filter((f) => mvtAvailableLayers.has(f.id))
|
||||||
.map((l) => LayoutSource.setupMvtSource(l, mapProperties, isDisplayed(l.id)))
|
.map((l) => ThemeSource.setupMvtSource(l, mapProperties, isDisplayed(l.id)))
|
||||||
const nonMvtSources = []
|
const nonMvtSources = []
|
||||||
const nonMvtLayers = osmLayers.filter((l) => !mvtAvailableLayers.has(l.id))
|
const nonMvtLayers = osmLayers.filter((l) => !mvtAvailableLayers.has(l.id))
|
||||||
|
|
||||||
const isLoading = new UIEventSource(false)
|
const isLoading = new UIEventSource(false)
|
||||||
|
|
||||||
const osmApiSource = LayoutSource.setupOsmApiSource(
|
const osmApiSource = ThemeSource.setupOsmApiSource(
|
||||||
osmLayers,
|
osmLayers,
|
||||||
bounds,
|
bounds,
|
||||||
zoom,
|
zoom,
|
||||||
|
@ -86,7 +86,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
||||||
nonMvtLayers.map((l) => l.id),
|
nonMvtLayers.map((l) => l.id),
|
||||||
" cannot be fetched from the cache server, defaulting to overpass/OSM-api"
|
" cannot be fetched from the cache server, defaulting to overpass/OSM-api"
|
||||||
)
|
)
|
||||||
overpassSource = LayoutSource.setupOverpass(osmLayers, bounds, zoom, featureSwitches)
|
overpassSource = ThemeSource.setupOverpass(osmLayers, bounds, zoom, featureSwitches)
|
||||||
nonMvtSources.push(overpassSource)
|
nonMvtSources.push(overpassSource)
|
||||||
supportsForceDownload.push(overpassSource)
|
supportsForceDownload.push(overpassSource)
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
||||||
osmApiSource?.isRunning?.addCallbackAndRun(() => setIsLoading())
|
osmApiSource?.isRunning?.addCallbackAndRun(() => setIsLoading())
|
||||||
|
|
||||||
const geojsonSources: UpdatableFeatureSource[] = geojsonlayers.map((l) =>
|
const geojsonSources: UpdatableFeatureSource[] = geojsonlayers.map((l) =>
|
||||||
LayoutSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id))
|
ThemeSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id))
|
||||||
)
|
)
|
||||||
|
|
||||||
super(...geojsonSources, ...Array.from(fromCache.values()), ...mvtSources, ...nonMvtSources)
|
super(...geojsonSources, ...Array.from(fromCache.values()), ...mvtSources, ...nonMvtSources)
|
||||||
|
@ -198,7 +198,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
||||||
zoom,
|
zoom,
|
||||||
bounds,
|
bounds,
|
||||||
layers: osmLayers,
|
layers: osmLayers,
|
||||||
widenFactor: featureSwitches.layoutToUse.widenFactor,
|
widenFactor: 1.5,
|
||||||
overpassUrl: featureSwitches.overpassUrl,
|
overpassUrl: featureSwitches.overpassUrl,
|
||||||
overpassTimeout: featureSwitches.overpassTimeout,
|
overpassTimeout: featureSwitches.overpassTimeout,
|
||||||
overpassMaxZoom: featureSwitches.overpassMaxZoom,
|
overpassMaxZoom: featureSwitches.overpassMaxZoom,
|
|
@ -2,7 +2,7 @@ import { ImageUploader, UploadResult } from "./ImageUploader"
|
||||||
import LinkImageAction from "../Osm/Actions/LinkImageAction"
|
import LinkImageAction from "../Osm/Actions/LinkImageAction"
|
||||||
import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore"
|
import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore"
|
||||||
import { OsmId, OsmTags } from "../../Models/OsmFeature"
|
import { OsmId, OsmTags } from "../../Models/OsmFeature"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Store, UIEventSource } from "../UIEventSource"
|
import { Store, UIEventSource } from "../UIEventSource"
|
||||||
import { OsmConnection } from "../Osm/OsmConnection"
|
import { OsmConnection } from "../Osm/OsmConnection"
|
||||||
import { Changes } from "../Osm/Changes"
|
import { Changes } from "../Osm/Changes"
|
||||||
|
@ -17,7 +17,7 @@ import { GeoOperations } from "../GeoOperations"
|
||||||
export class ImageUploadManager {
|
export class ImageUploadManager {
|
||||||
private readonly _uploader: ImageUploader
|
private readonly _uploader: ImageUploader
|
||||||
private readonly _featureProperties: FeaturePropertiesStore
|
private readonly _featureProperties: FeaturePropertiesStore
|
||||||
private readonly _layout: LayoutConfig
|
private readonly _theme: ThemeConfig
|
||||||
private readonly _indexedFeatures: IndexedFeatureSource
|
private readonly _indexedFeatures: IndexedFeatureSource
|
||||||
private readonly _gps: Store<GeolocationCoordinates | undefined>
|
private readonly _gps: Store<GeolocationCoordinates | undefined>
|
||||||
private readonly _uploadStarted: Map<string, UIEventSource<number>> = new Map()
|
private readonly _uploadStarted: Map<string, UIEventSource<number>> = new Map()
|
||||||
|
@ -31,7 +31,7 @@ export class ImageUploadManager {
|
||||||
private readonly _reportError: (message: (string | Error | XMLHttpRequest), extramessage?: string) => Promise<void>
|
private readonly _reportError: (message: (string | Error | XMLHttpRequest), extramessage?: string) => Promise<void>
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
layout: LayoutConfig,
|
layout: ThemeConfig,
|
||||||
uploader: ImageUploader,
|
uploader: ImageUploader,
|
||||||
featureProperties: FeaturePropertiesStore,
|
featureProperties: FeaturePropertiesStore,
|
||||||
osmConnection: OsmConnection,
|
osmConnection: OsmConnection,
|
||||||
|
@ -42,7 +42,7 @@ export class ImageUploadManager {
|
||||||
) {
|
) {
|
||||||
this._uploader = uploader
|
this._uploader = uploader
|
||||||
this._featureProperties = featureProperties
|
this._featureProperties = featureProperties
|
||||||
this._layout = layout
|
this._theme = layout
|
||||||
this._osmConnection = osmConnection
|
this._osmConnection = osmConnection
|
||||||
this._changes = changes
|
this._changes = changes
|
||||||
this._indexedFeatures = allFeatures
|
this._indexedFeatures = allFeatures
|
||||||
|
@ -131,7 +131,7 @@ export class ImageUploadManager {
|
||||||
const properties = this._featureProperties.getStore(featureId)
|
const properties = this._featureProperties.getStore(featureId)
|
||||||
|
|
||||||
const action = new LinkImageAction(featureId, uploadResult. key, uploadResult . value, properties, {
|
const action = new LinkImageAction(featureId, uploadResult. key, uploadResult . value, properties, {
|
||||||
theme: tags?.data?.["_orig_theme"] ?? this._layout.id,
|
theme: tags?.data?.["_orig_theme"] ?? this._theme.id,
|
||||||
changeType: "add-image",
|
changeType: "add-image",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { ExtraFuncParams, ExtraFunctions, ExtraFuncType } from "./ExtraFunctions
|
||||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||||
import { Feature } from "geojson"
|
import { Feature } from "geojson"
|
||||||
import FeaturePropertiesStore from "./FeatureSource/Actors/FeaturePropertiesStore"
|
import FeaturePropertiesStore from "./FeatureSource/Actors/FeaturePropertiesStore"
|
||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||||
import { GeoIndexedStoreForLayer } from "./FeatureSource/Actors/GeoIndexedStore"
|
import { GeoIndexedStoreForLayer } from "./FeatureSource/Actors/GeoIndexedStore"
|
||||||
import { IndexedFeatureSource } from "./FeatureSource/FeatureSource"
|
import { IndexedFeatureSource } from "./FeatureSource/FeatureSource"
|
||||||
import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
|
import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
|
||||||
|
@ -27,7 +27,7 @@ export default class MetaTagging {
|
||||||
>()
|
>()
|
||||||
private state: {
|
private state: {
|
||||||
readonly selectedElement: Store<Feature>
|
readonly selectedElement: Store<Feature>
|
||||||
readonly layout: LayoutConfig
|
readonly theme: ThemeConfig
|
||||||
readonly osmObjectDownloader: OsmObjectDownloader
|
readonly osmObjectDownloader: OsmObjectDownloader
|
||||||
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
||||||
readonly indexedFeatures: IndexedFeatureSource
|
readonly indexedFeatures: IndexedFeatureSource
|
||||||
|
@ -40,7 +40,7 @@ export default class MetaTagging {
|
||||||
|
|
||||||
constructor(state: {
|
constructor(state: {
|
||||||
readonly selectedElement: Store<Feature>
|
readonly selectedElement: Store<Feature>
|
||||||
readonly layout: LayoutConfig
|
readonly theme: ThemeConfig
|
||||||
readonly osmObjectDownloader: OsmObjectDownloader
|
readonly osmObjectDownloader: OsmObjectDownloader
|
||||||
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
||||||
readonly indexedFeatures: IndexedFeatureSource
|
readonly indexedFeatures: IndexedFeatureSource
|
||||||
|
@ -48,7 +48,7 @@ export default class MetaTagging {
|
||||||
}) {
|
}) {
|
||||||
this.state = state
|
this.state = state
|
||||||
const params = (this.params = MetaTagging.createExtraFuncParams(state))
|
const params = (this.params = MetaTagging.createExtraFuncParams(state))
|
||||||
for (const layer of state.layout.layers) {
|
for (const layer of state.theme.layers) {
|
||||||
if (layer.source === null) {
|
if (layer.source === null) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ export default class MetaTagging {
|
||||||
features,
|
features,
|
||||||
params,
|
params,
|
||||||
layer,
|
layer,
|
||||||
state.layout,
|
state.theme,
|
||||||
state.osmObjectDownloader,
|
state.osmObjectDownloader,
|
||||||
state.featureProperties
|
state.featureProperties
|
||||||
)
|
)
|
||||||
|
@ -115,7 +115,7 @@ export default class MetaTagging {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const state = this.state
|
const state = this.state
|
||||||
const layer = state.layout.getMatchingLayer(feature.properties)
|
const layer = state.theme.getMatchingLayer(feature.properties)
|
||||||
if (!layer) {
|
if (!layer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ export default class MetaTagging {
|
||||||
[feature],
|
[feature],
|
||||||
this.params,
|
this.params,
|
||||||
layer,
|
layer,
|
||||||
state.layout,
|
state.theme,
|
||||||
state.osmObjectDownloader,
|
state.osmObjectDownloader,
|
||||||
state.featureProperties,
|
state.featureProperties,
|
||||||
{
|
{
|
||||||
|
@ -161,7 +161,7 @@ export default class MetaTagging {
|
||||||
features: Feature[],
|
features: Feature[],
|
||||||
params: ExtraFuncParams,
|
params: ExtraFuncParams,
|
||||||
layer: LayerConfig,
|
layer: LayerConfig,
|
||||||
layout: LayoutConfig,
|
theme: ThemeConfig,
|
||||||
osmObjectDownloader: OsmObjectDownloader,
|
osmObjectDownloader: OsmObjectDownloader,
|
||||||
featurePropertiesStores?: FeaturePropertiesStore,
|
featurePropertiesStores?: FeaturePropertiesStore,
|
||||||
options?: {
|
options?: {
|
||||||
|
@ -190,7 +190,7 @@ export default class MetaTagging {
|
||||||
// The calculated functions - per layer - which add the new keys
|
// The calculated functions - per layer - which add the new keys
|
||||||
// Calculated functions are defined by the layer
|
// Calculated functions are defined by the layer
|
||||||
const layerFuncs = this.createRetaggingFunc(layer, ExtraFunctions.constructHelpers(params))
|
const layerFuncs = this.createRetaggingFunc(layer, ExtraFunctions.constructHelpers(params))
|
||||||
const state: MetataggingState = { layout, osmObjectDownloader }
|
const state: MetataggingState = { theme: theme, osmObjectDownloader }
|
||||||
|
|
||||||
let atLeastOneFeatureChanged = false
|
let atLeastOneFeatureChanged = false
|
||||||
let strictlyEvaluated = 0
|
let strictlyEvaluated = 0
|
||||||
|
@ -424,7 +424,7 @@ export default class MetaTagging {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window.location.pathname.endsWith("theme.html")) {
|
if (!Utils.runningFromConsole && !window.location.pathname.endsWith("theme.html")) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"Static MetataggingObject for theme is not set; using `new Function` (aka `eval`) to get calculated tags. This might trip up the CSP"
|
"Static MetataggingObject for theme is not set; using `new Function` (aka `eval`) to get calculated tags. This might trip up the CSP"
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,7 +7,7 @@ import CreateWayWithPointReuseAction, { MergePointConfig } from "./CreateWayWith
|
||||||
import { And } from "../../Tags/And"
|
import { And } from "../../Tags/And"
|
||||||
import { TagUtils } from "../../Tags/TagUtils"
|
import { TagUtils } from "../../Tags/TagUtils"
|
||||||
import { FeatureSource, IndexedFeatureSource } from "../../FeatureSource/FeatureSource"
|
import { FeatureSource, IndexedFeatureSource } from "../../FeatureSource/FeatureSource"
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Position } from "geojson"
|
import { Position } from "geojson"
|
||||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ export default class CreateMultiPolygonWithPointReuseAction
|
||||||
outerRingCoordinates: Position[],
|
outerRingCoordinates: Position[],
|
||||||
innerRingsCoordinates: Position[][],
|
innerRingsCoordinates: Position[][],
|
||||||
state: {
|
state: {
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
changes: Changes
|
changes: Changes
|
||||||
indexedFeatures: IndexedFeatureSource
|
indexedFeatures: IndexedFeatureSource
|
||||||
fullNodeDatabase?: FullNodeDatabaseSource
|
fullNodeDatabase?: FullNodeDatabaseSource
|
||||||
|
@ -43,7 +43,7 @@ export default class CreateMultiPolygonWithPointReuseAction
|
||||||
super(null, true)
|
super(null, true)
|
||||||
this._tags = [...tags, new Tag("type", "multipolygon")]
|
this._tags = [...tags, new Tag("type", "multipolygon")]
|
||||||
this.changeType = changeType
|
this.changeType = changeType
|
||||||
this.theme = state?.layout?.id ?? ""
|
this.theme = state?.theme?.id ?? ""
|
||||||
this.createOuterWay = new CreateWayWithPointReuseAction(
|
this.createOuterWay = new CreateWayWithPointReuseAction(
|
||||||
[],
|
[],
|
||||||
<[number, number][]>outerRingCoordinates,
|
<[number, number][]>outerRingCoordinates,
|
||||||
|
@ -55,7 +55,7 @@ export default class CreateMultiPolygonWithPointReuseAction
|
||||||
new CreateNewWayAction(
|
new CreateNewWayAction(
|
||||||
[],
|
[],
|
||||||
ringCoordinates.map(([lon, lat]) => ({ lat, lon })),
|
ringCoordinates.map(([lon, lat]) => ({ lat, lon })),
|
||||||
{ theme: state?.layout?.id }
|
{ theme: state?.theme?.id }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { FeatureSource, IndexedFeatureSource } from "../../FeatureSource/Feature
|
||||||
import StaticFeatureSource from "../../FeatureSource/Sources/StaticFeatureSource"
|
import StaticFeatureSource from "../../FeatureSource/Sources/StaticFeatureSource"
|
||||||
import CreateNewNodeAction from "./CreateNewNodeAction"
|
import CreateNewNodeAction from "./CreateNewNodeAction"
|
||||||
import CreateNewWayAction from "./CreateNewWayAction"
|
import CreateNewWayAction from "./CreateNewWayAction"
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||||
import { Position } from "geojson"
|
import { Position } from "geojson"
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ export default class CreateWayWithPointReuseAction
|
||||||
*/
|
*/
|
||||||
private readonly _coordinateInfo: CoordinateInfo[]
|
private readonly _coordinateInfo: CoordinateInfo[]
|
||||||
private readonly _state: {
|
private readonly _state: {
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
changes: Changes
|
changes: Changes
|
||||||
indexedFeatures: IndexedFeatureSource
|
indexedFeatures: IndexedFeatureSource
|
||||||
fullNodeDatabase?: FullNodeDatabaseSource
|
fullNodeDatabase?: FullNodeDatabaseSource
|
||||||
|
@ -80,7 +80,7 @@ export default class CreateWayWithPointReuseAction
|
||||||
tags: Tag[],
|
tags: Tag[],
|
||||||
coordinates: Position[],
|
coordinates: Position[],
|
||||||
state: {
|
state: {
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
changes: Changes
|
changes: Changes
|
||||||
indexedFeatures: IndexedFeatureSource
|
indexedFeatures: IndexedFeatureSource
|
||||||
fullNodeDatabase?: FullNodeDatabaseSource
|
fullNodeDatabase?: FullNodeDatabaseSource
|
||||||
|
@ -203,7 +203,7 @@ export default class CreateWayWithPointReuseAction
|
||||||
}
|
}
|
||||||
|
|
||||||
public async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
|
public async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
|
||||||
const theme = this._state?.layout?.id
|
const theme = this._state?.theme?.id
|
||||||
const allChanges: ChangeDescription[] = []
|
const allChanges: ChangeDescription[] = []
|
||||||
const nodeIdsToUse: { lat: number; lon: number; nodeId?: number }[] = []
|
const nodeIdsToUse: { lat: number; lon: number; nodeId?: number }[] = []
|
||||||
for (let i = 0; i < this._coordinateInfo.length; i++) {
|
for (let i = 0; i < this._coordinateInfo.length; i++) {
|
||||||
|
|
|
@ -217,7 +217,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
||||||
const url = `${
|
const url = `${
|
||||||
this.state.osmConnection?._oauth_config?.url ?? "https://api.openstreetmap.org"
|
this.state.osmConnection?._oauth_config?.url ?? "https://api.openstreetmap.org"
|
||||||
}/api/0.6/${this.wayToReplaceId}/full`
|
}/api/0.6/${this.wayToReplaceId}/full`
|
||||||
const rawData = await Utils.downloadJsonCached(url, 1000)
|
const rawData = await Utils.downloadJsonCached<{elements: any[]}>(url, 1000)
|
||||||
parsed = OsmObject.ParseObjects(rawData.elements)
|
parsed = OsmObject.ParseObjects(rawData.elements)
|
||||||
}
|
}
|
||||||
const allNodes = parsed.filter((o) => o.type === "node")
|
const allNodes = parsed.filter((o) => o.type === "node")
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Constants from "../../Models/Constants"
|
||||||
import FilterConfig, { FilterConfigOption } from "../../Models/ThemeConfig/FilterConfig"
|
import FilterConfig, { FilterConfigOption } from "../../Models/ThemeConfig/FilterConfig"
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
import LayerState from "../State/LayerState"
|
import LayerState from "../State/LayerState"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
|
|
||||||
export type FilterSearchResult = { option: FilterConfigOption, filter: FilterConfig, layer: LayerConfig, index: number }
|
export type FilterSearchResult = { option: FilterConfigOption, filter: FilterConfig, layer: LayerConfig, index: number }
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ export type FilterSearchResult = { option: FilterConfigOption, filter: FilterCon
|
||||||
* Searches matching filters
|
* Searches matching filters
|
||||||
*/
|
*/
|
||||||
export default class FilterSearch {
|
export default class FilterSearch {
|
||||||
private readonly _state: {layerState: LayerState, layout: LayoutConfig}
|
private readonly _state: {layerState: LayerState, theme: ThemeConfig}
|
||||||
|
|
||||||
constructor(state: {layerState: LayerState, layout: LayoutConfig}) {
|
constructor(state: {layerState: LayerState, theme: ThemeConfig}) {
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ export default class FilterSearch {
|
||||||
return query
|
return query
|
||||||
}).filter(q => q.length > 0)
|
}).filter(q => q.length > 0)
|
||||||
const possibleFilters: FilterSearchResult[] = []
|
const possibleFilters: FilterSearchResult[] = []
|
||||||
for (const layer of this._state.layout.layers) {
|
for (const layer of this._state.theme.layers) {
|
||||||
if (!Array.isArray(layer.filters)) {
|
if (!Array.isArray(layer.filters)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import SearchUtils from "./SearchUtils"
|
import SearchUtils from "./SearchUtils"
|
||||||
import ThemeSearch from "./ThemeSearch"
|
import ThemeSearch from "./ThemeSearch"
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
|
|
||||||
export default class LayerSearch {
|
export default class LayerSearch {
|
||||||
|
|
||||||
private readonly _layout: LayoutConfig
|
private readonly _theme: ThemeConfig
|
||||||
private readonly _layerWhitelist: Set<string>
|
private readonly _layerWhitelist: Set<string>
|
||||||
|
|
||||||
constructor(layout: LayoutConfig) {
|
constructor(theme: ThemeConfig) {
|
||||||
this._layout = layout
|
this._theme = theme
|
||||||
this._layerWhitelist = new Set(layout.layers
|
this._layerWhitelist = new Set(theme.layers
|
||||||
.filter(l => l.isNormal())
|
.filter(l => l.isNormal())
|
||||||
.map(l => l.id))
|
.map(l => l.id))
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,7 @@ export default class LayerSearch {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const keywords = ThemeSearch.officialThemes.layers[id]
|
const keywords = ThemeSearch.officialThemes.layers[id]
|
||||||
const distance = Math.min(...queryParts.map(q => SearchUtils.scoreKeywords(q, keywords)))
|
result[id] = Math.min(...queryParts.map(q => SearchUtils.scoreKeywords(q, keywords)))
|
||||||
result[id] = distance
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -44,7 +43,7 @@ export default class LayerSearch {
|
||||||
const asList: ({ layer: LayerConfig, score: number })[] = []
|
const asList: ({ layer: LayerConfig, score: number })[] = []
|
||||||
for (const layer in scores) {
|
for (const layer in scores) {
|
||||||
asList.push({
|
asList.push({
|
||||||
layer: this._layout.getLayer(layer),
|
layer: this._theme.getLayer(layer),
|
||||||
score: scores[layer],
|
score: scores[layer],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import LayoutConfig, { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig, { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Store } from "../UIEventSource"
|
import { Store } from "../UIEventSource"
|
||||||
import UserRelatedState from "../State/UserRelatedState"
|
import UserRelatedState from "../State/UserRelatedState"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
|
@ -10,7 +10,7 @@ import { OsmConnection } from "../Osm/OsmConnection"
|
||||||
|
|
||||||
|
|
||||||
type ThemeSearchScore = {
|
type ThemeSearchScore = {
|
||||||
theme: MinimalLayoutInformation,
|
theme: MinimalThemeInformation,
|
||||||
lowest: number,
|
lowest: number,
|
||||||
perLayer?: Record<string, number>,
|
perLayer?: Record<string, number>,
|
||||||
other: number,
|
other: number,
|
||||||
|
@ -20,10 +20,10 @@ type ThemeSearchScore = {
|
||||||
export default class ThemeSearch {
|
export default class ThemeSearch {
|
||||||
|
|
||||||
public static readonly officialThemes: {
|
public static readonly officialThemes: {
|
||||||
themes: MinimalLayoutInformation[],
|
themes: MinimalThemeInformation[],
|
||||||
layers: Record<string, Record<string, string[]>>
|
layers: Record<string, Record<string, string[]>>
|
||||||
} = <any> themeOverview
|
} = <any> themeOverview
|
||||||
public static readonly officialThemesById: Map<string, MinimalLayoutInformation> = new Map<string, MinimalLayoutInformation>()
|
public static readonly officialThemesById: Map<string, MinimalThemeInformation> = new Map<string, MinimalThemeInformation>()
|
||||||
static {
|
static {
|
||||||
for (const th of ThemeSearch.officialThemes.themes ?? []) {
|
for (const th of ThemeSearch.officialThemes.themes ?? []) {
|
||||||
ThemeSearch.officialThemesById.set(th.id, th)
|
ThemeSearch.officialThemesById.set(th.id, th)
|
||||||
|
@ -33,17 +33,17 @@ export default class ThemeSearch {
|
||||||
|
|
||||||
private readonly _knownHiddenThemes: Store<Set<string>>
|
private readonly _knownHiddenThemes: Store<Set<string>>
|
||||||
private readonly _layersToIgnore: string[]
|
private readonly _layersToIgnore: string[]
|
||||||
private readonly _otherThemes: MinimalLayoutInformation[]
|
private readonly _otherThemes: MinimalThemeInformation[]
|
||||||
|
|
||||||
constructor(state: {osmConnection: OsmConnection, layout: LayoutConfig}) {
|
constructor(state: {osmConnection: OsmConnection, theme: ThemeConfig}) {
|
||||||
this._layersToIgnore = state.layout.layers.filter(l => l.isNormal()).map(l => l.id)
|
this._layersToIgnore = state.theme.layers.filter(l => l.isNormal()).map(l => l.id)
|
||||||
this._knownHiddenThemes = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection).map(list => new Set(list))
|
this._knownHiddenThemes = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection).map(list => new Set(list))
|
||||||
this._otherThemes = ThemeSearch.officialThemes.themes
|
this._otherThemes = ThemeSearch.officialThemes.themes
|
||||||
.filter(th => th.id !== state.layout.id)
|
.filter(th => th.id !== state.theme.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public search(query: string, limit: number, threshold: number = 3): MinimalLayoutInformation[] {
|
public search(query: string, limit: number, threshold: number = 3): MinimalThemeInformation[] {
|
||||||
if (query.length < 1) {
|
if (query.length < 1) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ export default class ThemeSearch {
|
||||||
* @param ignoreLayers
|
* @param ignoreLayers
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private static scoreThemes(query: string, themes: MinimalLayoutInformation[], ignoreLayers: string[] = undefined): Record<string, ThemeSearchScore> {
|
private static scoreThemes(query: string, themes: MinimalThemeInformation[], ignoreLayers: string[] = undefined): Record<string, ThemeSearchScore> {
|
||||||
if (query?.length < 1) {
|
if (query?.length < 1) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
@ -147,13 +147,13 @@ export default class ThemeSearch {
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
public static sortedByLowestScores(search: string, themes: MinimalLayoutInformation[], ignoreLayers: string[] = []): ThemeSearchScore[] {
|
public static sortedByLowestScores(search: string, themes: MinimalThemeInformation[], ignoreLayers: string[] = []): ThemeSearchScore[] {
|
||||||
const scored = Object.values(this.scoreThemes(search, themes, ignoreLayers))
|
const scored = Object.values(this.scoreThemes(search, themes, ignoreLayers))
|
||||||
scored.sort((a, b) => a.lowest - b.lowest)
|
scored.sort((a, b) => a.lowest - b.lowest)
|
||||||
return scored
|
return scored
|
||||||
}
|
}
|
||||||
|
|
||||||
public static sortedByLowest(search: string, themes: MinimalLayoutInformation[], ignoreLayers: string[] = []): MinimalLayoutInformation[] {
|
public static sortedByLowest(search: string, themes: MinimalThemeInformation[], ignoreLayers: string[] = []): MinimalThemeInformation[] {
|
||||||
return this.sortedByLowestScores(search, themes, ignoreLayers)
|
return this.sortedByLowestScores(search, themes, ignoreLayers)
|
||||||
.map(th => th.theme)
|
.map(th => th.theme)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { TagUtils } from "./Tags/TagUtils"
|
||||||
import { Feature, LineString } from "geojson"
|
import { Feature, LineString } from "geojson"
|
||||||
import { OsmTags } from "../Models/OsmFeature"
|
import { OsmTags } from "../Models/OsmFeature"
|
||||||
import { UIEventSource } from "./UIEventSource"
|
import { UIEventSource } from "./UIEventSource"
|
||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||||
import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
|
import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
|
||||||
import countryToCurrency from "country-to-currency"
|
import countryToCurrency from "country-to-currency"
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import countryToCurrency from "country-to-currency"
|
||||||
* All elements that are needed to perform metatagging
|
* All elements that are needed to perform metatagging
|
||||||
*/
|
*/
|
||||||
export interface MetataggingState {
|
export interface MetataggingState {
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
osmObjectDownloader: OsmObjectDownloader
|
osmObjectDownloader: OsmObjectDownloader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +399,7 @@ export default class SimpleMetaTaggers {
|
||||||
},
|
},
|
||||||
(feature, _, __, state) => {
|
(feature, _, __, state) => {
|
||||||
const units = Utils.NoNull(
|
const units = Utils.NoNull(
|
||||||
[].concat(...(state?.layout?.layers?.map((layer) => layer.units) ?? []))
|
[].concat(...(state?.theme?.layers?.map((layer) => layer.units) ?? []))
|
||||||
)
|
)
|
||||||
if (units.length == 0) {
|
if (units.length == 0) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* The part of the global state which initializes the feature switches, based on default values and on the layoutToUse
|
* The part of the global state which initializes the feature switches, based on default values and on the theme
|
||||||
*/
|
*/
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { UIEventSource } from "../UIEventSource"
|
import { UIEventSource } from "../UIEventSource"
|
||||||
import { QueryParameters } from "../Web/QueryParameters"
|
import { QueryParameters } from "../Web/QueryParameters"
|
||||||
import Constants from "../../Models/Constants"
|
import Constants from "../../Models/Constants"
|
||||||
|
@ -45,10 +45,6 @@ export class OsmConnectionFeatureSwitches {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
/**
|
|
||||||
* The layout that is being used in this run
|
|
||||||
*/
|
|
||||||
public readonly layoutToUse: LayoutConfig
|
|
||||||
|
|
||||||
public readonly featureSwitchEnableLogin: UIEventSource<boolean>
|
public readonly featureSwitchEnableLogin: UIEventSource<boolean>
|
||||||
public readonly featureSwitchSearch: UIEventSource<boolean>
|
public readonly featureSwitchSearch: UIEventSource<boolean>
|
||||||
|
@ -74,9 +70,8 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
public readonly featureSwitchMorePrivacy: UIEventSource<boolean>
|
public readonly featureSwitchMorePrivacy: UIEventSource<boolean>
|
||||||
public readonly featureSwitchLayerDefault: UIEventSource<boolean>
|
public readonly featureSwitchLayerDefault: UIEventSource<boolean>
|
||||||
|
|
||||||
public constructor(layoutToUse?: LayoutConfig) {
|
public constructor(theme?: ThemeConfig) {
|
||||||
super()
|
super()
|
||||||
this.layoutToUse = layoutToUse
|
|
||||||
|
|
||||||
const legacyRewrite: Record<string, string | string[]> = {
|
const legacyRewrite: Record<string, string | string[]> = {
|
||||||
"fs-userbadge": "fs-enable-login",
|
"fs-userbadge": "fs-enable-login",
|
||||||
|
@ -102,7 +97,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
|
|
||||||
this.featureSwitchEnableLogin = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchEnableLogin = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-enable-login",
|
"fs-enable-login",
|
||||||
layoutToUse?.enableUserBadge ?? true,
|
theme?.enableUserBadge ?? true,
|
||||||
"Disables/Enables logging in and thus disables editing all together. This effectively puts MapComplete into read-only mode."
|
"Disables/Enables logging in and thus disables editing all together. This effectively puts MapComplete into read-only mode."
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -117,18 +112,18 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
|
|
||||||
this.featureSwitchSearch = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchSearch = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-search",
|
"fs-search",
|
||||||
layoutToUse?.enableSearch ?? true,
|
theme?.enableSearch ?? true,
|
||||||
"Disables/Enables the search bar"
|
"Disables/Enables the search bar"
|
||||||
)
|
)
|
||||||
this.featureSwitchBackgroundSelection = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchBackgroundSelection = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-background",
|
"fs-background",
|
||||||
layoutToUse?.enableBackgroundLayerSelection ?? true,
|
theme?.enableBackgroundLayerSelection ?? true,
|
||||||
"Disables/Enables the background layer control where a user can enable e.g. aerial imagery"
|
"Disables/Enables the background layer control where a user can enable e.g. aerial imagery"
|
||||||
)
|
)
|
||||||
|
|
||||||
this.featureSwitchFilter = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchFilter = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-filter",
|
"fs-filter",
|
||||||
layoutToUse?.enableLayers ?? true,
|
theme?.enableLayers ?? true,
|
||||||
"Disables/Enables the filter view where a user can enable/disable MapComplete-layers or filter for certain properties"
|
"Disables/Enables the filter view where a user can enable/disable MapComplete-layers or filter for certain properties"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -149,17 +144,17 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
)
|
)
|
||||||
this.featureSwitchBackToThemeOverview = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchBackToThemeOverview = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-homepage-link",
|
"fs-homepage-link",
|
||||||
layoutToUse?.enableMoreQuests ?? true,
|
theme?.enableMoreQuests ?? true,
|
||||||
"Disables/Enables the various links which go back to the index page with the theme overview"
|
"Disables/Enables the various links which go back to the index page with the theme overview"
|
||||||
)
|
)
|
||||||
this.featureSwitchShareScreen = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchShareScreen = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-share-screen",
|
"fs-share-screen",
|
||||||
layoutToUse?.enableShareScreen ?? true,
|
theme?.enableShareScreen ?? true,
|
||||||
"Disables/Enables the 'Share-screen'-tab in the welcome message"
|
"Disables/Enables the 'Share-screen'-tab in the welcome message"
|
||||||
)
|
)
|
||||||
this.featureSwitchGeolocation = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchGeolocation = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-geolocation",
|
"fs-geolocation",
|
||||||
layoutToUse?.enableGeolocation ?? true,
|
theme?.enableGeolocation ?? true,
|
||||||
"Disables/Enables the geolocation button"
|
"Disables/Enables the geolocation button"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -170,19 +165,19 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
)
|
)
|
||||||
this.featureSwitchShowAllQuestions = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchShowAllQuestions = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-all-questions",
|
"fs-all-questions",
|
||||||
layoutToUse?.enableShowAllQuestions ?? false,
|
theme?.enableShowAllQuestions ?? false,
|
||||||
"Always show all questions"
|
"Always show all questions"
|
||||||
)
|
)
|
||||||
|
|
||||||
this.featureSwitchEnableExport = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchEnableExport = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-export",
|
"fs-export",
|
||||||
layoutToUse?.enableExportButton ?? true,
|
theme?.enableExportButton ?? true,
|
||||||
"Enable the export as GeoJSON and CSV button"
|
"Enable the export as GeoJSON and CSV button"
|
||||||
)
|
)
|
||||||
|
|
||||||
this.featureSwitchCache = FeatureSwitchUtils.initSwitch(
|
this.featureSwitchCache = FeatureSwitchUtils.initSwitch(
|
||||||
"fs-cache",
|
"fs-cache",
|
||||||
layoutToUse?.enableCache ?? true,
|
theme?.enableCache ?? true,
|
||||||
"Enable/disable caching from localStorage"
|
"Enable/disable caching from localStorage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -209,13 +204,13 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
|
|
||||||
this.featureSwitchMorePrivacy = QueryParameters.GetBooleanQueryParameter(
|
this.featureSwitchMorePrivacy = QueryParameters.GetBooleanQueryParameter(
|
||||||
"moreprivacy",
|
"moreprivacy",
|
||||||
layoutToUse.enableMorePrivacy,
|
theme.enableMorePrivacy,
|
||||||
"If true, the location distance indication will not be written to the changeset and other privacy enhancing measures might be taken."
|
"If true, the location distance indication will not be written to the changeset and other privacy enhancing measures might be taken."
|
||||||
)
|
)
|
||||||
|
|
||||||
this.overpassUrl = QueryParameters.GetQueryParameter(
|
this.overpassUrl = QueryParameters.GetQueryParameter(
|
||||||
"overpassUrl",
|
"overpassUrl",
|
||||||
(layoutToUse?.overpassUrl ?? Constants.defaultOverpassUrls).join(","),
|
(theme?.overpassUrl ?? Constants.defaultOverpassUrls).join(","),
|
||||||
"Point mapcomplete to a different overpass-instance. Example: https://overpass-api.de/api/interpreter"
|
"Point mapcomplete to a different overpass-instance. Example: https://overpass-api.de/api/interpreter"
|
||||||
).sync(
|
).sync(
|
||||||
(param) => param?.split(","),
|
(param) => param?.split(","),
|
||||||
|
@ -226,7 +221,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
this.overpassTimeout = UIEventSource.asInt(
|
this.overpassTimeout = UIEventSource.asInt(
|
||||||
QueryParameters.GetQueryParameter(
|
QueryParameters.GetQueryParameter(
|
||||||
"overpassTimeout",
|
"overpassTimeout",
|
||||||
"" + layoutToUse?.overpassTimeout,
|
"" + theme?.overpassTimeout,
|
||||||
"Set a different timeout (in seconds) for queries in overpass"
|
"Set a different timeout (in seconds) for queries in overpass"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -234,7 +229,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
this.overpassMaxZoom = UIEventSource.asFloat(
|
this.overpassMaxZoom = UIEventSource.asFloat(
|
||||||
QueryParameters.GetQueryParameter(
|
QueryParameters.GetQueryParameter(
|
||||||
"overpassMaxZoom",
|
"overpassMaxZoom",
|
||||||
"" + layoutToUse?.overpassMaxZoom,
|
"" + theme?.overpassMaxZoom,
|
||||||
" point to switch between OSM-api and overpass"
|
" point to switch between OSM-api and overpass"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -242,14 +237,14 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||||
this.osmApiTileSize = UIEventSource.asInt(
|
this.osmApiTileSize = UIEventSource.asInt(
|
||||||
QueryParameters.GetQueryParameter(
|
QueryParameters.GetQueryParameter(
|
||||||
"osmApiTileSize",
|
"osmApiTileSize",
|
||||||
"" + layoutToUse?.osmApiTileSize,
|
"" + theme?.osmApiTileSize,
|
||||||
"Tilesize when the OSM-API is used to fetch data within a BBOX"
|
"Tilesize when the OSM-API is used to fetch data within a BBOX"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
this.backgroundLayerId = QueryParameters.GetQueryParameter(
|
this.backgroundLayerId = QueryParameters.GetQueryParameter(
|
||||||
"background",
|
"background",
|
||||||
layoutToUse?.defaultBackgroundId,
|
theme?.defaultBackgroundId,
|
||||||
[
|
[
|
||||||
"When set, load this raster layer (or a layer of this category) as background layer instead of using the default background. This is as if the user opened the background selection menu and selected the layer with the given id or category.",
|
"When set, load this raster layer (or a layer of this category) as background layer instead of using the default background. This is as if the user opened the background selection menu and selected the layer with the given id or category.",
|
||||||
"Most raster layers are based on the [editor layer index](https://github.com/osmlab/editor-layer-index)",
|
"Most raster layers are based on the [editor layer index](https://github.com/osmlab/editor-layer-index)",
|
||||||
|
|
|
@ -8,7 +8,7 @@ import ThemeSearch from "../Search/ThemeSearch"
|
||||||
import OpenStreetMapIdSearch from "../Search/OpenStreetMapIdSearch"
|
import OpenStreetMapIdSearch from "../Search/OpenStreetMapIdSearch"
|
||||||
import PhotonSearch from "../Search/PhotonSearch"
|
import PhotonSearch from "../Search/PhotonSearch"
|
||||||
import ThemeViewState from "../../Models/ThemeViewState"
|
import ThemeViewState from "../../Models/ThemeViewState"
|
||||||
import type { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import type { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Translation } from "../../UI/i18n/Translation"
|
import { Translation } from "../../UI/i18n/Translation"
|
||||||
import GeocodingFeatureSource from "../Search/GeocodingFeatureSource"
|
import GeocodingFeatureSource from "../Search/GeocodingFeatureSource"
|
||||||
import LayerSearch from "../Search/LayerSearch"
|
import LayerSearch from "../Search/LayerSearch"
|
||||||
|
@ -23,7 +23,7 @@ export default class SearchState {
|
||||||
public readonly searchIsFocused = new UIEventSource(false)
|
public readonly searchIsFocused = new UIEventSource(false)
|
||||||
public readonly suggestions: Store<SearchResult[]>
|
public readonly suggestions: Store<SearchResult[]>
|
||||||
public readonly filterSuggestions: Store<FilterSearchResult[]>
|
public readonly filterSuggestions: Store<FilterSearchResult[]>
|
||||||
public readonly themeSuggestions: Store<MinimalLayoutInformation[]>
|
public readonly themeSuggestions: Store<MinimalThemeInformation[]>
|
||||||
public readonly layerSuggestions: Store<LayerConfig[]>
|
public readonly layerSuggestions: Store<LayerConfig[]>
|
||||||
public readonly locationSearchers: ReadonlyArray<GeocodingProvider>
|
public readonly locationSearchers: ReadonlyArray<GeocodingProvider>
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ export default class SearchState {
|
||||||
const themeSearch = new ThemeSearch(state)
|
const themeSearch = new ThemeSearch(state)
|
||||||
this.themeSuggestions = this.searchTerm.mapD(query => themeSearch.search(query, 3))
|
this.themeSuggestions = this.searchTerm.mapD(query => themeSearch.search(query, 3))
|
||||||
|
|
||||||
const layerSearch = new LayerSearch(state.layout)
|
const layerSearch = new LayerSearch(state.theme)
|
||||||
this.layerSuggestions = this.searchTerm.mapD(query => layerSearch.search(query, 5))
|
this.layerSuggestions = this.searchTerm.mapD(query => layerSearch.search(query, 5))
|
||||||
|
|
||||||
const filterSearch = new FilterSearch(state)
|
const filterSearch = new FilterSearch(state)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import LayoutConfig, { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig, { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { OsmConnection } from "../Osm/OsmConnection"
|
import { OsmConnection } from "../Osm/OsmConnection"
|
||||||
import { MangroveIdentity } from "../Web/MangroveReviews"
|
import { MangroveIdentity } from "../Web/MangroveReviews"
|
||||||
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
||||||
|
@ -183,7 +183,7 @@ export default class UserRelatedState {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
osmConnection: OsmConnection,
|
osmConnection: OsmConnection,
|
||||||
layout?: LayoutConfig,
|
layout?: ThemeConfig,
|
||||||
featureSwitches?: FeatureSwitchState,
|
featureSwitches?: FeatureSwitchState,
|
||||||
mapProperties?: MapProperties,
|
mapProperties?: MapProperties,
|
||||||
) {
|
) {
|
||||||
|
@ -277,14 +277,14 @@ export default class UserRelatedState {
|
||||||
*
|
*
|
||||||
* @param themeInfo note that themeInfo.id should be the URL where it was found
|
* @param themeInfo note that themeInfo.id should be the URL where it was found
|
||||||
*/
|
*/
|
||||||
public addUnofficialTheme(themeInfo: MinimalLayoutInformation) {
|
public addUnofficialTheme(themeInfo: MinimalThemeInformation) {
|
||||||
const pref = this.osmConnection.getPreference("unofficial-theme-" + themeInfo.id)
|
const pref = this.osmConnection.getPreference("unofficial-theme-" + themeInfo.id)
|
||||||
this.osmConnection.isLoggedIn.when(
|
this.osmConnection.isLoggedIn.when(
|
||||||
() => pref.set(JSON.stringify(themeInfo))
|
() => pref.set(JSON.stringify(themeInfo))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUnofficialTheme(id: string): MinimalLayoutInformation | undefined {
|
public getUnofficialTheme(id: string): MinimalThemeInformation | undefined {
|
||||||
const pref = this.osmConnection.getPreference("unofficial-theme-" + id)
|
const pref = this.osmConnection.getPreference("unofficial-theme-" + id)
|
||||||
const str = pref.data
|
const str = pref.data
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ export default class UserRelatedState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public markLayoutAsVisited(layout: LayoutConfig) {
|
public markLayoutAsVisited(layout: ThemeConfig) {
|
||||||
if (!layout) {
|
if (!layout) {
|
||||||
console.error("Trying to mark a layout as visited, but ", layout, " got passed")
|
console.error("Trying to mark a layout as visited, but ", layout, " got passed")
|
||||||
return
|
return
|
||||||
|
@ -399,7 +399,7 @@ export default class UserRelatedState {
|
||||||
* This is inherently a dirty and chaotic method, as it shoves many properties into this EventSource
|
* This is inherently a dirty and chaotic method, as it shoves many properties into this EventSource
|
||||||
* */
|
* */
|
||||||
private initAmendedPrefs(
|
private initAmendedPrefs(
|
||||||
layout?: LayoutConfig,
|
layout?: ThemeConfig,
|
||||||
featureSwitches?: FeatureSwitchState,
|
featureSwitches?: FeatureSwitchState,
|
||||||
): UIEventSource<Record<string, string>> {
|
): UIEventSource<Record<string, string>> {
|
||||||
const amendedPrefs = new UIEventSource<Record<string, string>>({
|
const amendedPrefs = new UIEventSource<Record<string, string>>({
|
||||||
|
|
|
@ -30,6 +30,8 @@ export class LocalStorageSource {
|
||||||
return cached
|
return cached
|
||||||
}
|
}
|
||||||
let saved = defaultValue
|
let saved = defaultValue
|
||||||
|
if (!Utils.runningFromConsole) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
saved = localStorage.getItem(key)
|
saved = localStorage.getItem(key)
|
||||||
if (saved === "undefined") {
|
if (saved === "undefined") {
|
||||||
|
@ -38,6 +40,7 @@ export class LocalStorageSource {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Could not get value", key, "from local storage")
|
console.error("Could not get value", key, "from local storage")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const source = new UIEventSource<string>(saved ?? defaultValue, "localstorage:" + key)
|
const source = new UIEventSource<string>(saved ?? defaultValue, "localstorage:" + key)
|
||||||
|
|
||||||
source.addCallback((data) => {
|
source.addCallback((data) => {
|
||||||
|
|
|
@ -55,7 +55,7 @@ export default class Constants {
|
||||||
// The user journey states thresholds when a new feature gets unlocked
|
// The user journey states thresholds when a new feature gets unlocked
|
||||||
public static userJourney = {
|
public static userJourney = {
|
||||||
moreScreenUnlock: 1,
|
moreScreenUnlock: 1,
|
||||||
personalLayoutUnlock: 5,
|
personalThemeUnlock: 5,
|
||||||
historyLinkVisible: 10,
|
historyLinkVisible: 10,
|
||||||
deletePointsOfOthersUnlock: 20,
|
deletePointsOfOthersUnlock: 20,
|
||||||
tagsVisibleAt: 25,
|
tagsVisibleAt: 25,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Conversion, DesugaringStep } from "./Conversion"
|
import { Conversion, DesugaringStep } from "./Conversion"
|
||||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
import metapaths from "../../../assets/schemas/layoutconfigmeta.json"
|
import metapaths from "../../../assets/schemas/layoutconfigmeta.json"
|
||||||
import tagrenderingmetapaths from "../../../assets/schemas/questionabletagrenderingconfigmeta.json"
|
import tagrenderingmetapaths from "../../../assets/schemas/questionabletagrenderingconfigmeta.json"
|
||||||
|
@ -9,7 +9,7 @@ import { parse as parse_html } from "node-html-parser"
|
||||||
import { ConversionContext } from "./ConversionContext"
|
import { ConversionContext } from "./ConversionContext"
|
||||||
|
|
||||||
export class ExtractImages extends Conversion<
|
export class ExtractImages extends Conversion<
|
||||||
LayoutConfigJson,
|
ThemeConfigJson,
|
||||||
{ path: string; context: string }[]
|
{ path: string; context: string }[]
|
||||||
> {
|
> {
|
||||||
private static readonly layoutMetaPaths = metapaths.filter((mp) => {
|
private static readonly layoutMetaPaths = metapaths.filter((mp) => {
|
||||||
|
@ -109,7 +109,7 @@ export class ExtractImages extends Conversion<
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
convert(
|
convert(
|
||||||
json: LayoutConfigJson,
|
json: ThemeConfigJson,
|
||||||
context: ConversionContext
|
context: ConversionContext
|
||||||
): { path: string; context: string }[] {
|
): { path: string; context: string }[] {
|
||||||
const allFoundImages: { path: string; context: string }[] = []
|
const allFoundImages: { path: string; context: string }[] = []
|
||||||
|
@ -243,7 +243,7 @@ export class ExtractImages extends Conversion<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FixImages extends DesugaringStep<LayoutConfigJson> {
|
export class FixImages extends DesugaringStep<ThemeConfigJson> {
|
||||||
private readonly _knownImages: Set<string>
|
private readonly _knownImages: Set<string>
|
||||||
|
|
||||||
constructor(knownImages: Set<string>) {
|
constructor(knownImages: Set<string>) {
|
||||||
|
@ -289,7 +289,7 @@ export class FixImages extends DesugaringStep<LayoutConfigJson> {
|
||||||
* fixed.layers[0]["pointRendering"][0].marker[0].icon // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/TS_bolt.svg"
|
* fixed.layers[0]["pointRendering"][0].marker[0].icon // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/TS_bolt.svg"
|
||||||
* fixed.layers[0]["pointRendering"][0].iconBadges[0].then.mappings[0].then // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/Something.svg"
|
* fixed.layers[0]["pointRendering"][0].iconBadges[0].then.mappings[0].then // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/Something.svg"
|
||||||
*/
|
*/
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
let url: URL
|
let url: URL
|
||||||
try {
|
try {
|
||||||
url = new URL(json.id)
|
url = new URL(json.id)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
|
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
|
||||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||||
|
@ -257,12 +257,12 @@ export class UpdateLegacyLayer extends DesugaringStep<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UpdateLegacyTheme extends DesugaringStep<LayoutConfigJson> {
|
class UpdateLegacyTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("Small fixes in the theme config", ["roamingRenderings"], "UpdateLegacyTheme")
|
super("Small fixes in the theme config", ["roamingRenderings"], "UpdateLegacyTheme")
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
const oldThemeConfig = { ...json }
|
const oldThemeConfig = { ...json }
|
||||||
|
|
||||||
if (oldThemeConfig.socialImage === "") {
|
if (oldThemeConfig.socialImage === "") {
|
||||||
|
@ -311,7 +311,7 @@ class UpdateLegacyTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FixLegacyTheme extends Fuse<LayoutConfigJson> {
|
export class FixLegacyTheme extends Fuse<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"Fixes a legacy theme to the modern JSON format geared to humans. Syntactic sugars are kept (i.e. no tagRenderings are expandend, no dependencies are automatically gathered)",
|
"Fixes a legacy theme to the modern JSON format geared to humans. Syntactic sugars are kept (i.e. no tagRenderings are expandend, no dependencies are automatically gathered)",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
|
import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
|
||||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||||
import { PrepareLayer } from "./PrepareLayer"
|
import { PrepareLayer } from "./PrepareLayer"
|
||||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
|
@ -165,7 +165,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
class AddDefaultLayers extends DesugaringStep<ThemeConfigJson> {
|
||||||
private readonly _state: DesugaringContext
|
private readonly _state: DesugaringContext
|
||||||
|
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
|
@ -177,7 +177,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
const state = this._state
|
const state = this._state
|
||||||
json.layers = Utils.NoNull([...(json.layers ?? [])])
|
json.layers = Utils.NoNull([...(json.layers ?? [])])
|
||||||
const alreadyLoaded = new Set(json.layers.map((l) => l["id"]))
|
const alreadyLoaded = new Set(json.layers.map((l) => l["id"]))
|
||||||
|
@ -209,7 +209,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson> {
|
class AddContextToTranslationsInLayout extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too",
|
"Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too",
|
||||||
|
@ -218,8 +218,8 @@ class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson): LayoutConfigJson {
|
convert(json: ThemeConfigJson): ThemeConfigJson {
|
||||||
const conversion = new AddContextToTranslations<LayoutConfigJson>("themes:")
|
const conversion = new AddContextToTranslations<ThemeConfigJson>("themes:")
|
||||||
// The context is used to generate the 'context' in the translation .It _must_ be `json.id` to correctly link into weblate
|
// The context is used to generate the 'context' in the translation .It _must_ be `json.id` to correctly link into weblate
|
||||||
return conversion.convert(
|
return conversion.convert(
|
||||||
json,
|
json,
|
||||||
|
@ -228,7 +228,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
class ApplyOverrideAll extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
|
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
|
||||||
|
@ -237,7 +237,7 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, ctx: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, ctx: ConversionContext): ThemeConfigJson {
|
||||||
const overrideAll = json.overrideAll
|
const overrideAll = json.overrideAll
|
||||||
if (overrideAll === undefined) {
|
if (overrideAll === undefined) {
|
||||||
return json
|
return json
|
||||||
|
@ -278,7 +278,7 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
class AddDependencyLayersToTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
private readonly _state: DesugaringContext
|
private readonly _state: DesugaringContext
|
||||||
|
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
|
@ -390,7 +390,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
return dependenciesToAdd
|
return dependenciesToAdd
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(theme: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(theme: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
const state = this._state
|
const state = this._state
|
||||||
const allKnownLayers: Map<string, LayerConfigJson> = state.sharedLayers
|
const allKnownLayers: Map<string, LayerConfigJson> = state.sharedLayers
|
||||||
const knownTagRenderings: Map<string, TagRenderingConfigJson> = state.tagRenderings
|
const knownTagRenderings: Map<string, TagRenderingConfigJson> = state.tagRenderings
|
||||||
|
@ -428,7 +428,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PreparePersonalTheme extends DesugaringStep<LayoutConfigJson> {
|
class PreparePersonalTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
private readonly _state: DesugaringContext
|
private readonly _state: DesugaringContext
|
||||||
|
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
|
@ -436,7 +436,7 @@ class PreparePersonalTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
if (json.id !== "personal") {
|
if (json.id !== "personal") {
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
@ -452,7 +452,7 @@ class PreparePersonalTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson> {
|
class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"Generates a warning if a theme uses an unsubstituted layer",
|
"Generates a warning if a theme uses an unsubstituted layer",
|
||||||
|
@ -461,7 +461,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
if (json.hideFromOverview === true) {
|
if (json.hideFromOverview === true) {
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
@ -503,7 +503,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PostvalidateTheme extends DesugaringStep<LayoutConfigJson> {
|
class PostvalidateTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
private readonly _state: DesugaringContext
|
private readonly _state: DesugaringContext
|
||||||
|
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
|
@ -511,7 +511,7 @@ class PostvalidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
for (const l of json.layers) {
|
for (const l of json.layers) {
|
||||||
const layer = <LayerConfigJson>l
|
const layer = <LayerConfigJson>l
|
||||||
const basedOn = <string>layer["_basedOn"]
|
const basedOn = <string>layer["_basedOn"]
|
||||||
|
@ -582,7 +582,7 @@ class PostvalidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
export class PrepareTheme extends Fuse<ThemeConfigJson> {
|
||||||
private state: DesugaringContext
|
private state: DesugaringContext
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -616,7 +616,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
||||||
this.state = state
|
this.state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
const result = super.convert(json, context)
|
const result = super.convert(json, context)
|
||||||
if ((this.state.publicLayers?.size ?? 0) === 0) {
|
if ((this.state.publicLayers?.size ?? 0) === 0) {
|
||||||
// THis is a bootstrapping run, no need to already set this flag
|
// THis is a bootstrapping run, no need to already set this flag
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { DesugaringStep } from "./Conversion"
|
import { DesugaringStep } from "./Conversion"
|
||||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||||
import { AvailableRasterLayers } from "../../RasterLayers"
|
import { AvailableRasterLayers } from "../../RasterLayers"
|
||||||
import { ExtractImages } from "./FixImages"
|
import { ExtractImages } from "./FixImages"
|
||||||
import { ConversionContext } from "./ConversionContext"
|
import { ConversionContext } from "./ConversionContext"
|
||||||
import LayoutConfig from "../LayoutConfig"
|
import ThemeConfig from "../ThemeConfig"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
import { DetectDuplicatePresets, DoesImageExist, ValidateLanguageCompleteness } from "./Validation"
|
import { DetectDuplicatePresets, DoesImageExist, ValidateLanguageCompleteness } from "./Validation"
|
||||||
|
|
||||||
export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
/**
|
/**
|
||||||
* The paths where this layer is originally saved. Triggers some extra checks
|
* The paths where this layer is originally saved. Triggers some extra checks
|
||||||
* @private
|
* @private
|
||||||
|
@ -33,8 +33,8 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
const theme = new LayoutConfig(json, this._isBuiltin)
|
const theme = new ThemeConfig(json, this._isBuiltin)
|
||||||
{
|
{
|
||||||
// Legacy format checks
|
// Legacy format checks
|
||||||
if (this._isBuiltin) {
|
if (this._isBuiltin) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Bypass, Each, Fuse, On } from "./Conversion"
|
import { Bypass, Each, Fuse, On } from "./Conversion"
|
||||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||||
import Constants from "../../Constants"
|
import Constants from "../../Constants"
|
||||||
import { DoesImageExist, ValidateLayerConfig } from "./Validation"
|
import { DoesImageExist, ValidateLayerConfig } from "./Validation"
|
||||||
import { ValidateTheme } from "./ValidateTheme"
|
import { ValidateTheme } from "./ValidateTheme"
|
||||||
|
|
||||||
export class ValidateThemeAndLayers extends Fuse<LayoutConfigJson> {
|
export class ValidateThemeAndLayers extends Fuse<ThemeConfigJson> {
|
||||||
constructor(
|
constructor(
|
||||||
doesImageExist: DoesImageExist,
|
doesImageExist: DoesImageExist,
|
||||||
path: string,
|
path: string,
|
||||||
|
|
|
@ -4,8 +4,8 @@ import LayerConfig from "../LayerConfig"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
import Constants from "../../Constants"
|
import Constants from "../../Constants"
|
||||||
import { Translation } from "../../../UI/i18n/Translation"
|
import { Translation } from "../../../UI/i18n/Translation"
|
||||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||||
import LayoutConfig from "../LayoutConfig"
|
import ThemeConfig from "../ThemeConfig"
|
||||||
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
||||||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||||
import { And } from "../../../Logic/Tags/And"
|
import { And } from "../../../Logic/Tags/And"
|
||||||
|
@ -23,7 +23,7 @@ import { PrevalidateLayer } from "./PrevalidateLayer"
|
||||||
import { AvailableRasterLayers } from "../../RasterLayers"
|
import { AvailableRasterLayers } from "../../RasterLayers"
|
||||||
import { eliCategory } from "../../RasterLayerProperties"
|
import { eliCategory } from "../../RasterLayerProperties"
|
||||||
|
|
||||||
export class ValidateLanguageCompleteness extends DesugaringStep<LayoutConfig> {
|
export class ValidateLanguageCompleteness extends DesugaringStep<ThemeConfig> {
|
||||||
private readonly _languages: string[]
|
private readonly _languages: string[]
|
||||||
|
|
||||||
constructor(...languages: string[]) {
|
constructor(...languages: string[]) {
|
||||||
|
@ -35,7 +35,7 @@ export class ValidateLanguageCompleteness extends DesugaringStep<LayoutConfig> {
|
||||||
this._languages = languages ?? ["en"]
|
this._languages = languages ?? ["en"]
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(obj: LayoutConfig, context: ConversionContext): LayoutConfig {
|
convert(obj: ThemeConfig, context: ConversionContext): ThemeConfig {
|
||||||
const origLayers = obj.layers
|
const origLayers = obj.layers
|
||||||
obj.layers = [...obj.layers].filter((l) => l["id"] !== "favourite")
|
obj.layers = [...obj.layers].filter((l) => l["id"] !== "favourite")
|
||||||
const translations = Translation.ExtractAllTranslationsFrom(obj)
|
const translations = Translation.ExtractAllTranslationsFrom(obj)
|
||||||
|
@ -128,7 +128,7 @@ export class DoesImageExist extends DesugaringStep<string> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OverrideShadowingCheck extends DesugaringStep<LayoutConfigJson> {
|
class OverrideShadowingCheck extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"Checks that an 'overrideAll' does not override a single override",
|
"Checks that an 'overrideAll' does not override a single override",
|
||||||
|
@ -137,7 +137,7 @@ class OverrideShadowingCheck extends DesugaringStep<LayoutConfigJson> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
const overrideAll = json.overrideAll
|
const overrideAll = json.overrideAll
|
||||||
if (overrideAll === undefined) {
|
if (overrideAll === undefined) {
|
||||||
return json
|
return json
|
||||||
|
@ -170,12 +170,12 @@ class OverrideShadowingCheck extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MiscThemeChecks extends DesugaringStep<LayoutConfigJson> {
|
class MiscThemeChecks extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("Miscelleanous checks on the theme", [], "MiscThemesChecks")
|
super("Miscelleanous checks on the theme", [], "MiscThemesChecks")
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||||
if (json.id !== "personal" && (json.layers === undefined || json.layers.length === 0)) {
|
if (json.id !== "personal" && (json.layers === undefined || json.layers.length === 0)) {
|
||||||
context.err("The theme " + json.id + " has no 'layers' defined")
|
context.err("The theme " + json.id + " has no 'layers' defined")
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ class MiscThemeChecks extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PrevalidateTheme extends Fuse<LayoutConfigJson> {
|
export class PrevalidateTheme extends Fuse<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"Various consistency checks on the raw JSON",
|
"Various consistency checks on the raw JSON",
|
||||||
|
@ -905,7 +905,7 @@ export class ValidateFilter extends DesugaringStep<FilterConfigJson> {
|
||||||
|
|
||||||
export class DetectDuplicateFilters extends DesugaringStep<{
|
export class DetectDuplicateFilters extends DesugaringStep<{
|
||||||
layers: LayerConfigJson[]
|
layers: LayerConfigJson[]
|
||||||
themes: LayoutConfigJson[]
|
themes: ThemeConfigJson[]
|
||||||
}> {
|
}> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
|
@ -916,15 +916,15 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(
|
convert(
|
||||||
json: { layers: LayerConfigJson[]; themes: LayoutConfigJson[] },
|
json: { layers: LayerConfigJson[]; themes: ThemeConfigJson[] },
|
||||||
context: ConversionContext,
|
context: ConversionContext,
|
||||||
): { layers: LayerConfigJson[]; themes: LayoutConfigJson[] } {
|
): { layers: LayerConfigJson[]; themes: ThemeConfigJson[] } {
|
||||||
const { layers, themes } = json
|
const { layers, themes } = json
|
||||||
const perOsmTag = new Map<
|
const perOsmTag = new Map<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
layer: LayerConfigJson
|
layer: LayerConfigJson
|
||||||
layout: LayoutConfigJson | undefined
|
theme: ThemeConfigJson | undefined
|
||||||
filter: FilterConfigJson
|
filter: FilterConfigJson
|
||||||
}[]
|
}[]
|
||||||
>()
|
>()
|
||||||
|
@ -955,10 +955,10 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let msg = "Possible duplicate filter: " + key
|
let msg = "Possible duplicate filter: " + key
|
||||||
for (const { filter, layer, layout } of value) {
|
for (const { filter, layer, theme } of value) {
|
||||||
let id = ""
|
let id = ""
|
||||||
if (layout !== undefined) {
|
if (theme !== undefined) {
|
||||||
id = layout.id + ":"
|
id = theme.id + ":"
|
||||||
}
|
}
|
||||||
msg += `\n - ${id}${layer.id}.${filter.id}`
|
msg += `\n - ${id}${layer.id}.${filter.id}`
|
||||||
}
|
}
|
||||||
|
@ -977,11 +977,11 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
layer: LayerConfigJson
|
layer: LayerConfigJson
|
||||||
layout: LayoutConfigJson | undefined
|
theme: ThemeConfigJson | undefined
|
||||||
filter: FilterConfigJson
|
filter: FilterConfigJson
|
||||||
}[]
|
}[]
|
||||||
>,
|
>,
|
||||||
layout?: LayoutConfigJson | undefined,
|
theme?: ThemeConfigJson | undefined,
|
||||||
): void {
|
): void {
|
||||||
if (layer.filter === undefined || layer.filter === null) {
|
if (layer.filter === undefined || layer.filter === null) {
|
||||||
return
|
return
|
||||||
|
@ -1009,14 +1009,14 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
||||||
perOsmTag.get(key).push({
|
perOsmTag.get(key).push({
|
||||||
layer,
|
layer,
|
||||||
filter,
|
filter,
|
||||||
layout,
|
theme,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DetectDuplicatePresets extends DesugaringStep<LayoutConfig> {
|
export class DetectDuplicatePresets extends DesugaringStep<ThemeConfig> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"Detects mappings which have identical (english) names or identical mappings.",
|
"Detects mappings which have identical (english) names or identical mappings.",
|
||||||
|
@ -1025,7 +1025,7 @@ export class DetectDuplicatePresets extends DesugaringStep<LayoutConfig> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfig, context: ConversionContext): LayoutConfig {
|
convert(json: ThemeConfig, context: ConversionContext): ThemeConfig {
|
||||||
const presets: PresetConfig[] = [].concat(...json.layers.map((l) => l.presets))
|
const presets: PresetConfig[] = [].concat(...json.layers.map((l) => l.presets))
|
||||||
|
|
||||||
const enNames = presets.map((p) => p.title.textFor("en"))
|
const enNames = presets.map((p) => p.title.textFor("en"))
|
||||||
|
@ -1074,7 +1074,7 @@ export class DetectDuplicatePresets extends DesugaringStep<LayoutConfig> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ValidateThemeEnsemble extends Conversion<
|
export class ValidateThemeEnsemble extends Conversion<
|
||||||
LayoutConfig[],
|
ThemeConfig[],
|
||||||
Map<
|
Map<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
|
@ -1093,7 +1093,7 @@ export class ValidateThemeEnsemble extends Conversion<
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(
|
convert(
|
||||||
json: LayoutConfig[],
|
json: ThemeConfig[],
|
||||||
context: ConversionContext,
|
context: ConversionContext,
|
||||||
): Map<
|
): Map<
|
||||||
string,
|
string,
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default class FilterConfig {
|
||||||
const fields: { name: string; type: ValidatorType }[] = (option.fields ?? []).map((f, i) => {
|
const fields: { name: string; type: ValidatorType }[] = (option.fields ?? []).map((f, i) => {
|
||||||
const type = <ValidatorType> f.type ?? "regex"
|
const type = <ValidatorType> f.type ?? "regex"
|
||||||
if(Validators.availableTypes.indexOf(type) < 0){
|
if(Validators.availableTypes.indexOf(type) < 0){
|
||||||
throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance(type, <any>Validators.availableTypes, x => x).slice(0, 3)}`
|
throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance(type, <ReadonlyArray<string>>Validators.availableTypes, x => x).slice(0, 3)}`
|
||||||
}
|
}
|
||||||
// Type is validated against 'ValidatedTextField' in Validation.ts, in ValidateFilterConfig
|
// Type is validated against 'ValidatedTextField' in Validation.ts, in ValidateFilterConfig
|
||||||
if (f.name === undefined || f.name === "" || f.name.match(/[a-z0-9_-]+/) == null) {
|
if (f.name === undefined || f.name === "" || f.name.match(/[a-z0-9_-]+/) == null) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Translatable } from "./Translatable"
|
||||||
*
|
*
|
||||||
* General remark: a type (string | any) indicates either a fixed or a translatable string.
|
* General remark: a type (string | any) indicates either a fixed or a translatable string.
|
||||||
*/
|
*/
|
||||||
export interface LayoutConfigJson {
|
export interface ThemeConfigJson {
|
||||||
/**
|
/**
|
||||||
* question: What is the id of this layout?
|
* question: What is the id of this layout?
|
||||||
*
|
*
|
|
@ -1,5 +1,5 @@
|
||||||
import { Translation } from "../../UI/i18n/Translation"
|
import { Translation } from "../../UI/i18n/Translation"
|
||||||
import { LayoutConfigJson } from "./Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "./Json/ThemeConfigJson"
|
||||||
import LayerConfig from "./LayerConfig"
|
import LayerConfig from "./LayerConfig"
|
||||||
import { LayerConfigJson } from "./Json/LayerConfigJson"
|
import { LayerConfigJson } from "./Json/LayerConfigJson"
|
||||||
import Constants from "../Constants"
|
import Constants from "../Constants"
|
||||||
|
@ -13,7 +13,7 @@ import { Translatable } from "./Json/Translatable"
|
||||||
/**
|
/**
|
||||||
* Minimal information about a theme
|
* Minimal information about a theme
|
||||||
**/
|
**/
|
||||||
export class MinimalLayoutInformation {
|
export class MinimalThemeInformation {
|
||||||
id: string
|
id: string
|
||||||
icon: string
|
icon: string
|
||||||
title: Translatable
|
title: Translatable
|
||||||
|
@ -27,7 +27,7 @@ export class MinimalLayoutInformation {
|
||||||
/**
|
/**
|
||||||
* Minimal information about a theme
|
* Minimal information about a theme
|
||||||
**/
|
**/
|
||||||
export class LayoutInformation {
|
export class ThemeInformation {
|
||||||
id: string
|
id: string
|
||||||
icon: string
|
icon: string
|
||||||
title: Translatable | Translation
|
title: Translatable | Translation
|
||||||
|
@ -39,7 +39,7 @@ export class LayoutInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default class LayoutConfig implements LayoutInformation {
|
export default class ThemeConfig implements ThemeInformation {
|
||||||
public static readonly defaultSocialImage = "assets/SocialImage.png"
|
public static readonly defaultSocialImage = "assets/SocialImage.png"
|
||||||
public readonly id: string
|
public readonly id: string
|
||||||
public readonly credits?: string
|
public readonly credits?: string
|
||||||
|
@ -57,7 +57,6 @@ export default class LayoutConfig implements LayoutInformation {
|
||||||
public readonly startZoom: number
|
public readonly startZoom: number
|
||||||
public readonly startLat: number
|
public readonly startLat: number
|
||||||
public readonly startLon: number
|
public readonly startLon: number
|
||||||
public widenFactor: number
|
|
||||||
public defaultBackgroundId?: string
|
public defaultBackgroundId?: string
|
||||||
public layers: LayerConfig[]
|
public layers: LayerConfig[]
|
||||||
public tileLayerSources: (RasterLayerProperties & { defaultState?: true | boolean })[]
|
public tileLayerSources: (RasterLayerProperties & { defaultState?: true | boolean })[]
|
||||||
|
@ -92,11 +91,11 @@ export default class LayoutConfig implements LayoutInformation {
|
||||||
public readonly definitionRaw?: string
|
public readonly definitionRaw?: string
|
||||||
|
|
||||||
private readonly layersDict: Map<string, LayerConfig>
|
private readonly layersDict: Map<string, LayerConfig>
|
||||||
private readonly source: LayoutConfigJson
|
private readonly source: ThemeConfigJson
|
||||||
public readonly enableCache: boolean
|
public readonly enableCache: boolean
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
json: LayoutConfigJson,
|
json: ThemeConfigJson,
|
||||||
official = true,
|
official = true,
|
||||||
options?: {
|
options?: {
|
||||||
definedAtUrl?: string
|
definedAtUrl?: string
|
||||||
|
@ -167,7 +166,7 @@ export default class LayoutConfig implements LayoutInformation {
|
||||||
? undefined
|
? undefined
|
||||||
: new Translation(json.descriptionTail, "themes:" + context + ".descriptionTail")
|
: new Translation(json.descriptionTail, "themes:" + context + ".descriptionTail")
|
||||||
this.icon = json.icon
|
this.icon = json.icon
|
||||||
this.socialImage = json.socialImage ?? LayoutConfig.defaultSocialImage
|
this.socialImage = json.socialImage ?? ThemeConfig.defaultSocialImage
|
||||||
if (this.socialImage === "") {
|
if (this.socialImage === "") {
|
||||||
if (official) {
|
if (official) {
|
||||||
throw "Theme " + json.id + " has empty string as social image"
|
throw "Theme " + json.id + " has empty string as social image"
|
||||||
|
@ -176,7 +175,6 @@ export default class LayoutConfig implements LayoutInformation {
|
||||||
this.startZoom = json.startZoom
|
this.startZoom = json.startZoom
|
||||||
this.startLat = json.startLat
|
this.startLat = json.startLat
|
||||||
this.startLon = json.startLon
|
this.startLon = json.startLon
|
||||||
this.widenFactor = 1.5
|
|
||||||
|
|
||||||
this.defaultBackgroundId = json.defaultBackgroundId
|
this.defaultBackgroundId = json.defaultBackgroundId
|
||||||
this.tileLayerSources = json.tileLayerSources ?? []
|
this.tileLayerSources = json.tileLayerSources ?? []
|
|
@ -1,4 +1,4 @@
|
||||||
import LayoutConfig from "./ThemeConfig/LayoutConfig"
|
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"
|
||||||
|
@ -18,7 +18,7 @@ import UserRelatedState from "../Logic/State/UserRelatedState"
|
||||||
import LayerConfig from "./ThemeConfig/LayerConfig"
|
import LayerConfig from "./ThemeConfig/LayerConfig"
|
||||||
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
|
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
|
||||||
import { AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils } from "./RasterLayers"
|
import { AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils } from "./RasterLayers"
|
||||||
import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource"
|
import ThemeSource from "../Logic/FeatureSource/Sources/ThemeSource"
|
||||||
import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource"
|
import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource"
|
||||||
import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore"
|
import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore"
|
||||||
import PerLayerFeatureSourceSplitter from "../Logic/FeatureSource/PerLayerFeatureSourceSplitter"
|
import PerLayerFeatureSourceSplitter from "../Logic/FeatureSource/PerLayerFeatureSourceSplitter"
|
||||||
|
@ -80,7 +80,7 @@ import { PanoramaxUploader } from "../Logic/ImageProviders/Panoramax"
|
||||||
* It ties up all the needed elements and starts some actors.
|
* It ties up all the needed elements and starts some actors.
|
||||||
*/
|
*/
|
||||||
export default class ThemeViewState implements SpecialVisualizationState {
|
export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
readonly layout: LayoutConfig
|
readonly theme: ThemeConfig
|
||||||
readonly map: UIEventSource<MlMap>
|
readonly map: UIEventSource<MlMap>
|
||||||
readonly changes: Changes
|
readonly changes: Changes
|
||||||
readonly featureSwitches: FeatureSwitchState
|
readonly featureSwitches: FeatureSwitchState
|
||||||
|
@ -104,7 +104,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
readonly fullNodeDatabase?: FullNodeDatabaseSource
|
readonly fullNodeDatabase?: FullNodeDatabaseSource
|
||||||
|
|
||||||
readonly historicalUserLocations: WritableFeatureSource<Feature<Point>>
|
readonly historicalUserLocations: WritableFeatureSource<Feature<Point>>
|
||||||
readonly indexedFeatures: IndexedFeatureSource & LayoutSource
|
readonly indexedFeatures: IndexedFeatureSource & ThemeSource
|
||||||
readonly currentView: FeatureSource<Feature<Polygon>>
|
readonly currentView: FeatureSource<Feature<Polygon>>
|
||||||
readonly featuresInView: FeatureSource
|
readonly featuresInView: FeatureSource
|
||||||
readonly favourites: FavouritesFeatureSource
|
readonly favourites: FavouritesFeatureSource
|
||||||
|
@ -160,9 +160,9 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
*/
|
*/
|
||||||
public readonly featureSummary: SummaryTileSourceRewriter
|
public readonly featureSummary: SummaryTileSourceRewriter
|
||||||
|
|
||||||
constructor(layout: LayoutConfig, mvtAvailableLayers: Set<string>) {
|
constructor(layout: ThemeConfig, mvtAvailableLayers: Set<string>) {
|
||||||
Utils.initDomPurify()
|
Utils.initDomPurify()
|
||||||
this.layout = layout
|
this.theme = layout
|
||||||
this.featureSwitches = new FeatureSwitchState(layout)
|
this.featureSwitches = new FeatureSwitchState(layout)
|
||||||
this.guistate = new MenuState(
|
this.guistate = new MenuState(
|
||||||
this.featureSwitches.featureSwitchWelcomeMessage.data,
|
this.featureSwitches.featureSwitchWelcomeMessage.data,
|
||||||
|
@ -218,7 +218,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
|
|
||||||
{
|
{
|
||||||
const overlayLayerStates = new Map<string, { isDisplayed: UIEventSource<boolean> }>()
|
const overlayLayerStates = new Map<string, { isDisplayed: UIEventSource<boolean> }>()
|
||||||
for (const rasterInfo of this.layout.tileLayerSources) {
|
for (const rasterInfo of this.theme.tileLayerSources) {
|
||||||
const isDisplayed = QueryParameters.GetBooleanQueryParameter(
|
const isDisplayed = QueryParameters.GetBooleanQueryParameter(
|
||||||
"overlay-" + rasterInfo.id,
|
"overlay-" + rasterInfo.id,
|
||||||
rasterInfo.defaultState ?? true,
|
rasterInfo.defaultState ?? true,
|
||||||
|
@ -236,11 +236,11 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
* A bit tricky, as this is heavily intertwined with the 'changes'-element, which generates a stream of new and changed features too
|
* A bit tricky, as this is heavily intertwined with the 'changes'-element, which generates a stream of new and changed features too
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (this.layout.layers.some((l) => l._needsFullNodeDatabase)) {
|
if (this.theme.layers.some((l) => l._needsFullNodeDatabase)) {
|
||||||
this.fullNodeDatabase = new FullNodeDatabaseSource()
|
this.fullNodeDatabase = new FullNodeDatabaseSource()
|
||||||
}
|
}
|
||||||
|
|
||||||
const layoutSource = new LayoutSource(
|
const layoutSource = new ThemeSource(
|
||||||
layout.layers,
|
layout.layers,
|
||||||
this.featureSwitches,
|
this.featureSwitches,
|
||||||
this.mapProperties,
|
this.mapProperties,
|
||||||
|
@ -340,7 +340,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.lastClickObject = new LastClickFeatureSource(
|
this.lastClickObject = new LastClickFeatureSource(
|
||||||
this.layout,
|
this.theme,
|
||||||
this.mapProperties.lastClickLocation,
|
this.mapProperties.lastClickLocation,
|
||||||
this.userRelatedState.addNewFeatureMode,
|
this.userRelatedState.addNewFeatureMode,
|
||||||
)
|
)
|
||||||
|
@ -414,7 +414,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
const storage = new SaveFeatureSourceToLocalStorage(
|
const storage = new SaveFeatureSourceToLocalStorage(
|
||||||
this.osmConnection.Backend(),
|
this.osmConnection.Backend(),
|
||||||
fs.layer.layerDef.id,
|
fs.layer.layerDef.id,
|
||||||
LayoutSource.fromCacheZoomLevel,
|
ThemeSource.fromCacheZoomLevel,
|
||||||
fs,
|
fs,
|
||||||
this.featureProperties,
|
this.featureProperties,
|
||||||
fs.layer.layerDef.maxAgeOfCache,
|
fs.layer.layerDef.maxAgeOfCache,
|
||||||
|
@ -509,7 +509,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.userRelatedState.markLayoutAsVisited(this.layout)
|
this.userRelatedState.markLayoutAsVisited(this.theme)
|
||||||
|
|
||||||
this.selectedElement.addCallback((selected) => {
|
this.selectedElement.addCallback((selected) => {
|
||||||
if (selected === undefined) {
|
if (selected === undefined) {
|
||||||
|
@ -517,8 +517,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
if (this.theme.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
||||||
Utils.LoadCustomCss(this.layout.customCss)
|
Utils.LoadCustomCss(this.theme.customCss)
|
||||||
}
|
}
|
||||||
|
|
||||||
Hash.hash.addCallbackAndRunD((hash) => {
|
Hash.hash.addCallbackAndRunD((hash) => {
|
||||||
|
@ -738,11 +738,11 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
/**
|
/**
|
||||||
* MaxZoom for the summary layer
|
* MaxZoom for the summary layer
|
||||||
*/
|
*/
|
||||||
const normalLayers = this.layout.layers.filter(l => l.isNormal())
|
const normalLayers = this.theme.layers.filter(l => l.isNormal())
|
||||||
|
|
||||||
const maxzoom = Math.min(...normalLayers.map((l) => l.minzoom))
|
const maxzoom = Math.min(...normalLayers.map((l) => l.minzoom))
|
||||||
|
|
||||||
const layers = this.layout.layers.filter(
|
const layers = this.theme.layers.filter(
|
||||||
(l) =>
|
(l) =>
|
||||||
Constants.priviliged_layers.indexOf(<any>l.id) < 0 &&
|
Constants.priviliged_layers.indexOf(<any>l.id) < 0 &&
|
||||||
l.source.geojsonSource === undefined &&
|
l.source.geojsonSource === undefined &&
|
||||||
|
@ -796,8 +796,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
|
|
||||||
|
|
||||||
this.closestFeatures.registerSource(specialLayers.favourite, "favourite")
|
this.closestFeatures.registerSource(specialLayers.favourite, "favourite")
|
||||||
if (this.layout?.lockLocation) {
|
if (this.theme?.lockLocation) {
|
||||||
const bbox = new BBox(<any>this.layout.lockLocation)
|
const bbox = new BBox(<any>this.theme.lockLocation)
|
||||||
this.mapProperties.maxbounds.setData(bbox)
|
this.mapProperties.maxbounds.setData(bbox)
|
||||||
ShowDataLayer.showRange(
|
ShowDataLayer.showRange(
|
||||||
this.map,
|
this.map,
|
||||||
|
@ -805,7 +805,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
this.featureSwitches.featureSwitchIsTesting,
|
this.featureSwitches.featureSwitchIsTesting,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const currentViewLayer = this.layout.layers.find((l) => l.id === "current_view")
|
const currentViewLayer = this.theme.layers.find((l) => l.id === "current_view")
|
||||||
if (currentViewLayer?.tagRenderings?.length > 0) {
|
if (currentViewLayer?.tagRenderings?.length > 0) {
|
||||||
const params = MetaTagging.createExtraFuncParams(this)
|
const params = MetaTagging.createExtraFuncParams(this)
|
||||||
this.featureProperties.trackFeatureSource(specialLayers.current_view)
|
this.featureProperties.trackFeatureSource(specialLayers.current_view)
|
||||||
|
@ -814,7 +814,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
features,
|
features,
|
||||||
params,
|
params,
|
||||||
currentViewLayer,
|
currentViewLayer,
|
||||||
this.layout,
|
this.theme,
|
||||||
this.osmObjectDownloader,
|
this.osmObjectDownloader,
|
||||||
this.featureProperties,
|
this.featureProperties,
|
||||||
)
|
)
|
||||||
|
@ -909,9 +909,9 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
*/
|
*/
|
||||||
private initActors() {
|
private initActors() {
|
||||||
|
|
||||||
if (!this.layout.official) {
|
if (!this.theme.official) {
|
||||||
// Add custom themes to the "visited custom themes"
|
// Add custom themes to the "visited custom themes"
|
||||||
const th = this.layout
|
const th = this.theme
|
||||||
this.userRelatedState.addUnofficialTheme({
|
this.userRelatedState.addUnofficialTheme({
|
||||||
id: th.id,
|
id: th.id,
|
||||||
icon: th.icon,
|
icon: th.icon,
|
||||||
|
@ -945,7 +945,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
this.selectedElement.addCallbackD(selected => {
|
this.selectedElement.addCallbackD(selected => {
|
||||||
const [osm_type, osm_id] = selected.properties.id.split("/")
|
const [osm_type, osm_id] = selected.properties.id.split("/")
|
||||||
const [lon, lat] = GeoOperations.centerpointCoordinates(selected)
|
const [lon, lat] = GeoOperations.centerpointCoordinates(selected)
|
||||||
const layer = this.layout.getMatchingLayer(selected.properties)
|
const layer = this.theme.getMatchingLayer(selected.properties)
|
||||||
|
|
||||||
const nameOptions = [
|
const nameOptions = [
|
||||||
selected?.properties?.name,
|
selected?.properties?.name,
|
||||||
|
@ -987,7 +987,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches the appropriate layer - will first try if a special layer matches; if not, a normal layer will be used by delegating to the layout
|
* Searches the appropriate layer - will first try if a special layer matches; if not, a normal layer will be used by delegating to the theme
|
||||||
*/
|
*/
|
||||||
public getMatchingLayer(properties: Record<string, string>) {
|
public getMatchingLayer(properties: Record<string, string>) {
|
||||||
|
|
||||||
|
@ -1002,15 +1002,15 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
return UserRelatedState.usersettingsConfig
|
return UserRelatedState.usersettingsConfig
|
||||||
}
|
}
|
||||||
if (id.startsWith(LastClickFeatureSource.newPointElementId)) {
|
if (id.startsWith(LastClickFeatureSource.newPointElementId)) {
|
||||||
return this.layout.layers.find((l) => l.id === "last_click")
|
return this.theme.layers.find((l) => l.id === "last_click")
|
||||||
}
|
}
|
||||||
if (id.startsWith("search_result")) {
|
if (id.startsWith("search_result")) {
|
||||||
return GeocodingUtils.searchLayer
|
return GeocodingUtils.searchLayer
|
||||||
}
|
}
|
||||||
if (id === "location_track") {
|
if (id === "location_track") {
|
||||||
return this.layout.layers.find((l) => l.id === "gps_track")
|
return this.theme.layers.find((l) => l.id === "gps_track")
|
||||||
}
|
}
|
||||||
return this.layout.getMatchingLayer(properties)
|
return this.theme.getMatchingLayer(properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async reportError(message: string | Error | XMLHttpRequest, extramessage: string = "") {
|
public async reportError(message: string | Error | XMLHttpRequest, extramessage: string = "") {
|
||||||
|
@ -1059,7 +1059,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
stacktrace,
|
stacktrace,
|
||||||
message: "" + message,
|
message: "" + message,
|
||||||
layout: this.layout.id,
|
theme: this.theme.id,
|
||||||
version: Constants.vNumber,
|
version: Constants.vNumber,
|
||||||
language: this.userRelatedState.language.data,
|
language: this.userRelatedState.language.data,
|
||||||
username: this.osmConnection.userDetails.data?.name,
|
username: this.osmConnection.userDetails.data?.name,
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
import Constants from "../Models/Constants"
|
import Constants from "../Models/Constants"
|
||||||
import { ImmutableStore, Store, Stores, UIEventSource } from "../Logic/UIEventSource"
|
import { ImmutableStore, Store, Stores, UIEventSource } from "../Logic/UIEventSource"
|
||||||
import ThemesList from "./BigComponents/ThemesList.svelte"
|
import ThemesList from "./BigComponents/ThemesList.svelte"
|
||||||
import { MinimalLayoutInformation } from "../Models/ThemeConfig/LayoutConfig"
|
import { MinimalThemeInformation } from "../Models/ThemeConfig/ThemeConfig"
|
||||||
import Eye from "../assets/svg/Eye.svelte"
|
import Eye from "../assets/svg/Eye.svelte"
|
||||||
import LoginButton from "./Base/LoginButton.svelte"
|
import LoginButton from "./Base/LoginButton.svelte"
|
||||||
import Mastodon from "../assets/svg/Mastodon.svelte"
|
import Mastodon from "../assets/svg/Mastodon.svelte"
|
||||||
|
@ -46,16 +46,16 @@
|
||||||
|
|
||||||
let searchIsFocused = new UIEventSource(true)
|
let searchIsFocused = new UIEventSource(true)
|
||||||
|
|
||||||
const officialThemes: MinimalLayoutInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === false)
|
const officialThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === false)
|
||||||
const hiddenThemes: MinimalLayoutInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === true)
|
const hiddenThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === true)
|
||||||
let visitedHiddenThemes: Store<MinimalLayoutInformation[]> = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection)
|
let visitedHiddenThemes: Store<MinimalThemeInformation[]> = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection)
|
||||||
.map((knownIds) => hiddenThemes.filter((theme) =>
|
.map((knownIds) => hiddenThemes.filter((theme) =>
|
||||||
knownIds.indexOf(theme.id) >= 0 || state.osmConnection.userDetails.data.name === "Pieter Vander Vennet"
|
knownIds.indexOf(theme.id) >= 0 || state.osmConnection.userDetails.data.name === "Pieter Vander Vennet"
|
||||||
))
|
))
|
||||||
|
|
||||||
const customThemes: Store<MinimalLayoutInformation[]> = Stores.ListStabilized<string>(state.installedUserThemes)
|
const customThemes: Store<MinimalThemeInformation[]> = Stores.ListStabilized<string>(state.installedUserThemes)
|
||||||
.mapD(stableIds => Utils.NoNullInplace(stableIds.map(id => state.getUnofficialTheme(id))))
|
.mapD(stableIds => Utils.NoNullInplace(stableIds.map(id => state.getUnofficialTheme(id))))
|
||||||
function filtered(themes: Store<MinimalLayoutInformation[]>): Store<MinimalLayoutInformation[]> {
|
function filtered(themes: Store<MinimalThemeInformation[]>): Store<MinimalThemeInformation[]> {
|
||||||
return searchStable.map(search => {
|
return searchStable.map(search => {
|
||||||
if (!search) {
|
if (!search) {
|
||||||
return themes.data
|
return themes.data
|
||||||
|
@ -74,9 +74,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let officialSearched : Store<MinimalLayoutInformation[]>= filtered(new ImmutableStore(officialThemes))
|
let officialSearched : Store<MinimalThemeInformation[]>= filtered(new ImmutableStore(officialThemes))
|
||||||
let hiddenSearched: Store<MinimalLayoutInformation[]> = filtered(visitedHiddenThemes)
|
let hiddenSearched: Store<MinimalThemeInformation[]> = filtered(visitedHiddenThemes)
|
||||||
let customSearched: Store<MinimalLayoutInformation[]> = filtered(customThemes)
|
let customSearched: Store<MinimalThemeInformation[]> = filtered(customThemes)
|
||||||
|
|
||||||
|
|
||||||
let searchIsFocussed = new UIEventSource(false)
|
let searchIsFocussed = new UIEventSource(false)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
|
|
||||||
let layoutToUse = state.layout
|
let layoutToUse = state.theme
|
||||||
let iconAttributions: string[] = layoutToUse.getUsedImages()
|
let iconAttributions: string[] = layoutToUse.getUsedImages()
|
||||||
|
|
||||||
const allLicenses = {}
|
const allLicenses = {}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
|
|
||||||
const t = Translations.t.general.attribution
|
const t = Translations.t.general.attribution
|
||||||
const layoutToUse = state.layout
|
const layoutToUse = state.theme
|
||||||
|
|
||||||
let maintainer: Translation = undefined
|
let maintainer: Translation = undefined
|
||||||
if (layoutToUse.credits !== undefined && layoutToUse.credits !== "") {
|
if (layoutToUse.credits !== undefined && layoutToUse.credits !== "") {
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
{#if maintainer !== undefined}
|
{#if maintainer !== undefined}
|
||||||
<div class="flex items-center gap-x-2">
|
<div class="flex items-center gap-x-2">
|
||||||
<Marker icons={state.layout.icon} size="h-8 w-8 shrink-0" />
|
<Marker icons={state.theme.icon} size="h-8 w-8 shrink-0" />
|
||||||
<Tr t={maintainer} />
|
<Tr t={maintainer} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
import Icon from "../Map/Icon.svelte"
|
import Icon from "../Map/Icon.svelte"
|
||||||
|
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
let theme = state.layout?.id ?? ""
|
let theme = state.theme?.id ?? ""
|
||||||
let config: ExtraLinkConfig = state.layout.extraLink
|
let config: ExtraLinkConfig = state.theme.extraLink
|
||||||
let basepath = window.location.host
|
let basepath = window.location.host
|
||||||
let showWelcomeMessageSwitch = state.featureSwitches.featureSwitchWelcomeMessage
|
let showWelcomeMessageSwitch = state.featureSwitches.featureSwitchWelcomeMessage
|
||||||
const isIframe = Utils.isIframe
|
const isIframe = Utils.isIframe
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
{#if config.text}
|
{#if config.text}
|
||||||
<Tr t={config.text} />
|
<Tr t={config.text} />
|
||||||
{:else}
|
{:else}
|
||||||
<Tr t={t.screenToSmall.Subs({ theme: state.layout.title })} />
|
<Tr t={t.screenToSmall.Subs({ theme: state.theme.title })} />
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
export let state: ThemeViewState
|
export let state: ThemeViewState
|
||||||
export let onlyLink: boolean
|
export let onlyLink: boolean
|
||||||
|
|
||||||
let layout = state.layout
|
let theme = state.theme
|
||||||
|
|
||||||
let allEnabled: boolean
|
let allEnabled: boolean
|
||||||
let allDisabled: boolean
|
let allDisabled: boolean
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#each layout.layers as layer}
|
{#each theme.layers as layer}
|
||||||
<Filterview
|
<Filterview
|
||||||
{state}
|
{state}
|
||||||
zoomlevel={state.mapProperties.zoom}
|
zoomlevel={state.mapProperties.zoom}
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#each layout.tileLayerSources as tilesource}
|
{#each theme.tileLayerSources as tilesource}
|
||||||
<OverlayToggle
|
<OverlayToggle
|
||||||
layerproperties={tilesource}
|
layerproperties={tilesource}
|
||||||
state={state.overlayLayerStates.get(tilesource.id)}
|
state={state.overlayLayerStates.get(tilesource.id)}
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
|
|
||||||
let usersettingslayer = new LayerConfig(<LayerConfigJson>usersettings, "usersettings", true)
|
let usersettingslayer = new LayerConfig(<LayerConfigJson>usersettings, "usersettings", true)
|
||||||
|
|
||||||
let layout = state.layout
|
let theme = state.theme
|
||||||
let featureSwitches = state.featureSwitches
|
let featureSwitches = state.featureSwitches
|
||||||
let showHome = featureSwitches.featureSwitchBackToThemeOverview
|
let showHome = featureSwitches.featureSwitchBackToThemeOverview
|
||||||
let pg = state.guistate.pageStates
|
let pg = state.guistate.pageStates
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
<!-- All shown components are set by 'usersettings.json', which happily uses some special visualisations created specifically for it -->
|
<!-- All shown components are set by 'usersettings.json', which happily uses some special visualisations created specifically for it -->
|
||||||
<LoginToggle {state}>
|
<LoginToggle {state}>
|
||||||
<div class="flex flex-col" slot="not-logged-in">
|
<div class="flex flex-col" slot="not-logged-in">
|
||||||
<LanguagePicker availableLanguages={layout.language} />
|
<LanguagePicker availableLanguages={theme.language} />
|
||||||
<Tr cls="alert" t={Translations.t.userinfo.notLoggedIn} />
|
<Tr cls="alert" t={Translations.t.userinfo.notLoggedIn} />
|
||||||
<LoginButton clss="primary" osmConnection={state.osmConnection} />
|
<LoginButton clss="primary" osmConnection={state.osmConnection} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -161,12 +161,12 @@
|
||||||
|
|
||||||
<Page {onlyLink} shown={pg.about_theme}>
|
<Page {onlyLink} shown={pg.about_theme}>
|
||||||
<svelte:fragment slot="link">
|
<svelte:fragment slot="link">
|
||||||
<Marker size="h-7 w-7" icons={layout.icon} />
|
<Marker size="h-7 w-7" icons={theme.icon} />
|
||||||
<Tr t={t.showIntroduction} />
|
<Tr t={t.showIntroduction} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="header">
|
<svelte:fragment slot="header">
|
||||||
<Marker size="h-8 w-8 mr-3" icons={layout.icon} />
|
<Marker size="h-8 w-8 mr-3" icons={theme.icon} />
|
||||||
<Tr t={layout.title} />
|
<Tr t={theme.title} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<ThemeIntroPanel {state} />
|
<ThemeIntroPanel {state} />
|
||||||
</Page>
|
</Page>
|
||||||
|
@ -193,25 +193,25 @@
|
||||||
</Page>
|
</Page>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if layout.official}
|
{#if theme.official}
|
||||||
<a
|
<a
|
||||||
class="flex"
|
class="flex"
|
||||||
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
|
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
|
||||||
layout.id +
|
theme.id +
|
||||||
".md"}
|
".md"}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<DocumentMagnifyingGlass class="h-6 w-6" />
|
<DocumentMagnifyingGlass class="h-6 w-6" />
|
||||||
<Tr
|
<Tr
|
||||||
t={Translations.t.general.attribution.openThemeDocumentation.Subs({
|
t={Translations.t.general.attribution.openThemeDocumentation.Subs({
|
||||||
name: layout.title,
|
name: theme.title,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a class="flex" href={Utils.OsmChaLinkFor(31, layout.id)} target="_blank">
|
<a class="flex" href={Utils.OsmChaLinkFor(31, theme.id)} target="_blank">
|
||||||
<DocumentChartBar class="h-6 w-6" />
|
<DocumentChartBar class="h-6 w-6" />
|
||||||
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: layout.title })} />
|
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: theme.title })} />
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</SidebarUnit>
|
</SidebarUnit>
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
* In some cases (local deploys, custom themes), we need to set the URL to `/theme.html?layout=xyz` instead of `/xyz?...`
|
* In some cases (local deploys, custom themes), we need to set the URL to `/theme.html?layout=xyz` instead of `/xyz?...`
|
||||||
* Note that the 'layout='-param will be included automatically
|
* Note that the 'layout='-param will be included automatically
|
||||||
*/
|
*/
|
||||||
let needsThemeRedirect = url.port !== "" || url.hostname.match(/^[0-9]/) || !state.layout.official
|
let needsThemeRedirect = url.port !== "" || url.hostname.match(/^[0-9]/) || !state.theme.official
|
||||||
let layoutId = state.layout.id
|
let layoutId = state.theme.id
|
||||||
let baseLink = `${url.protocol}//${url.host}/${needsThemeRedirect ? "theme.html" : layoutId}?`
|
let baseLink = `${url.protocol}//${url.host}/${needsThemeRedirect ? "theme.html" : layoutId}?`
|
||||||
|
|
||||||
let showWelcomeMessage = true
|
let showWelcomeMessage = true
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
enableBackground: boolean,
|
enableBackground: boolean,
|
||||||
enableGeolocation: boolean
|
enableGeolocation: boolean
|
||||||
) {
|
) {
|
||||||
const layout = state.layout
|
const layout = state.theme
|
||||||
let excluded = Utils.NoNull([
|
let excluded = Utils.NoNull([
|
||||||
showWelcomeMessage ? undefined : "fs-welcome-message",
|
showWelcomeMessage ? undefined : "fs-welcome-message",
|
||||||
enableLogin ? undefined : "fs-enable-login",
|
enableLogin ? undefined : "fs-enable-login",
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
${
|
${
|
||||||
enableGeolocation ? 'allow="geolocation"' : ""
|
enableGeolocation ? 'allow="geolocation"' : ""
|
||||||
} width="100%" height="100%" style="min-width: 250px; min-height: 250px"
|
} width="100%" height="100%" style="min-width: 250px; min-height: 250px"
|
||||||
title="${state.layout.title?.txt ?? "MapComplete"} with MapComplete">
|
title="${state.theme.title?.txt ?? "MapComplete"} with MapComplete">
|
||||||
</iframe>`
|
</iframe>`
|
||||||
|
|
||||||
Array.from(state.layerState.filteredLayers.values()).forEach((flayer) =>
|
Array.from(state.layerState.filteredLayers.values()).forEach((flayer) =>
|
||||||
|
@ -163,7 +163,7 @@
|
||||||
<Tr t={tr.stateIsIncluded} />
|
<Tr t={tr.stateIsIncluded} />
|
||||||
<a
|
<a
|
||||||
class="inline-block w-fit cursor-pointer"
|
class="inline-block w-fit cursor-pointer"
|
||||||
on:click={() => state.guistate.filtersPanelIsOpened.set(true)}
|
on:click={() => state.guistate.pageStates.filter.set(true)}
|
||||||
>
|
>
|
||||||
<Tr t={tr.openLayers} />
|
<Tr t={tr.openLayers} />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
export let i: number = undefined
|
export let i: number = undefined
|
||||||
let id = feature.properties.id
|
let id = feature.properties.id
|
||||||
let tags = state.featureProperties.getStore(id)
|
let tags = state.featureProperties.getStore(id)
|
||||||
let layer: LayerConfig = state.layout.getMatchingLayer(tags.data)
|
let layer: LayerConfig = state.theme.getMatchingLayer(tags.data)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span class="inline-flex gap-x-1">
|
<span class="inline-flex gap-x-1">
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ImmutableStore, Store } from "../../Logic/UIEventSource"
|
import { ImmutableStore, Store } from "../../Logic/UIEventSource"
|
||||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import type { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import type { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import Tr from "../Base/Tr.svelte"
|
import Tr from "../Base/Tr.svelte"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import Marker from "../Map/Marker.svelte"
|
import Marker from "../Map/Marker.svelte"
|
||||||
|
|
||||||
export let theme: MinimalLayoutInformation & {isOfficial?: boolean}
|
export let theme: MinimalThemeInformation & {isOfficial?: boolean}
|
||||||
let isCustom: boolean = theme.id.startsWith("https://") || theme.id.startsWith("http://")
|
let isCustom: boolean = theme.id.startsWith("https://") || theme.id.startsWith("http://")
|
||||||
export let state: { layoutToUse?: { id: string }; osmConnection: OsmConnection }
|
export let state: { layoutToUse?: { id: string }; osmConnection: OsmConnection }
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* The theme introduction panel
|
* The theme introduction panel
|
||||||
*/
|
*/
|
||||||
export let state: ThemeViewState
|
export let state: ThemeViewState
|
||||||
let layout = state.layout
|
let theme = state.theme
|
||||||
|
|
||||||
let geolocation = state.geolocation.geolocationState
|
let geolocation = state.geolocation.geolocationState
|
||||||
let geopermission: Store<GeolocationPermissionState> = geolocation.permission
|
let geopermission: Store<GeolocationPermissionState> = geolocation.permission
|
||||||
|
@ -42,16 +42,16 @@
|
||||||
<div>
|
<div>
|
||||||
<!-- Intro, description, ... -->
|
<!-- Intro, description, ... -->
|
||||||
|
|
||||||
<Tr t={layout.description} />
|
<Tr t={theme.description} />
|
||||||
|
|
||||||
<If condition={state.featureSwitches.featureSwitchEnableLogin}>
|
<If condition={state.featureSwitches.featureSwitchEnableLogin}>
|
||||||
<Tr t={Translations.t.general.welcomeExplanation.general} />
|
<Tr t={Translations.t.general.welcomeExplanation.general} />
|
||||||
{#if layout.layers.some((l) => l.presets?.length > 0)}
|
{#if theme.layers.some((l) => l.presets?.length > 0)}
|
||||||
<Tr t={Translations.t.general.welcomeExplanation.addNew} />
|
<Tr t={Translations.t.general.welcomeExplanation.addNew} />
|
||||||
{/if}
|
{/if}
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<Tr t={layout.descriptionTail} />
|
<Tr t={theme.descriptionTail} />
|
||||||
|
|
||||||
<!-- Buttons: open map, go to location, search -->
|
<!-- Buttons: open map, go to location, search -->
|
||||||
<NextButton
|
<NextButton
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import ThemeButton from "./ThemeButton.svelte"
|
import ThemeButton from "./ThemeButton.svelte"
|
||||||
import { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import Tr from "../Base/Tr.svelte"
|
import Tr from "../Base/Tr.svelte"
|
||||||
|
|
||||||
export let search: UIEventSource<string>
|
export let search: UIEventSource<string>
|
||||||
export let themes: MinimalLayoutInformation[]
|
export let themes: MinimalThemeInformation[]
|
||||||
export let state: { osmConnection: OsmConnection }
|
export let state: { osmConnection: OsmConnection }
|
||||||
|
|
||||||
export let hasSelection : boolean = true
|
export let hasSelection : boolean = true
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import { Translation } from "../i18n/Translation"
|
import { Translation } from "../i18n/Translation"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import Invalid from "../../assets/svg/Invalid.svelte"
|
import Invalid from "../../assets/svg/Invalid.svelte"
|
||||||
import Tr from "../Base/Tr.svelte"
|
import Tr from "../Base/Tr.svelte"
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
export let trace: (title: string) => string
|
export let trace: (title: string) => string
|
||||||
export let state: {
|
export let state: {
|
||||||
layout: LayoutConfig
|
layout: ThemeConfig
|
||||||
osmConnection: OsmConnection
|
osmConnection: OsmConnection
|
||||||
readonly featureSwitchUserbadge: Store<boolean>
|
readonly featureSwitchUserbadge: Store<boolean>
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
new Tag(key, externalProperties[key]),
|
new Tag(key, externalProperties[key]),
|
||||||
tags.data,
|
tags.data,
|
||||||
{
|
{
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
changeType: "import",
|
changeType: "import",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
currentStep = "applying_all"
|
currentStep = "applying_all"
|
||||||
const tagsToApply = missing.data.map((k) => new Tag(k, externalProperties[k]))
|
const tagsToApply = missing.data.map((k) => new Tag(k, externalProperties[k]))
|
||||||
const change = new ChangeTagAction(tags.data.id, new And(tagsToApply), tags.data, {
|
const change = new ChangeTagAction(tags.data.id, new And(tagsToApply), tags.data, {
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
changeType: "import",
|
changeType: "import",
|
||||||
})
|
})
|
||||||
await state.changes.applyChanges(await change.CreateChangeDescriptions())
|
await state.changes.applyChanges(await change.CreateChangeDescriptions())
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
const gpsIsDisplayed = gpsLayer.isDisplayed.data
|
const gpsIsDisplayed = gpsLayer.isDisplayed.data
|
||||||
try {
|
try {
|
||||||
gpsLayer.isDisplayed.setData(false)
|
gpsLayer.isDisplayed.setData(false)
|
||||||
const name = state.layout.id
|
const name = state.theme.id
|
||||||
|
|
||||||
const title = `MapComplete_${name}_export_${new Date()
|
const title = `MapComplete_${name}_export_${new Date()
|
||||||
.toISOString()
|
.toISOString()
|
||||||
|
|
|
@ -156,7 +156,7 @@ export default class DownloadHelper {
|
||||||
private getCleanGeoJsonPerLayer(includeMetaData: boolean): Map<string, Feature[]> {
|
private getCleanGeoJsonPerLayer(includeMetaData: boolean): Map<string, Feature[]> {
|
||||||
const state = this._state
|
const state = this._state
|
||||||
const featuresPerLayer = new Map<string, any[]>()
|
const featuresPerLayer = new Map<string, any[]>()
|
||||||
const neededLayers = state.layout.layers.filter((l) => l.source !== null).map((l) => l.id)
|
const neededLayers = state.theme.layers.filter((l) => l.source !== null).map((l) => l.id)
|
||||||
const bbox = state.mapProperties.bounds.data
|
const bbox = state.mapProperties.bounds.data
|
||||||
|
|
||||||
for (const neededLayer of neededLayers) {
|
for (const neededLayer of neededLayers) {
|
||||||
|
@ -186,7 +186,7 @@ export default class DownloadHelper {
|
||||||
createImage(key: string, width: string, height: string): HTMLImageElement {
|
createImage(key: string, width: string, height: string): HTMLImageElement {
|
||||||
const img = document.createElement("img")
|
const img = document.createElement("img")
|
||||||
const sources = {
|
const sources = {
|
||||||
layouticon: this._state.layout.icon,
|
layouticon: this._state.theme.icon,
|
||||||
}
|
}
|
||||||
img.src = sources[key]
|
img.src = sources[key]
|
||||||
if (!img.src) {
|
if (!img.src) {
|
||||||
|
|
|
@ -38,10 +38,10 @@
|
||||||
return downloadHelper.createImage(key, width, height)
|
return downloadHelper.createImage(key, width, height)
|
||||||
},
|
},
|
||||||
textSubstitutions: <Record<string, string | Translation>>{
|
textSubstitutions: <Record<string, string | Translation>>{
|
||||||
"layout.title": state.layout.title,
|
"layout.title": state.theme.title,
|
||||||
layoutid: state.layout.id,
|
layoutid: state.theme.id,
|
||||||
title: state.layout.title,
|
title: state.theme.title,
|
||||||
layoutImg: state.layout.icon,
|
layoutImg: state.theme.icon,
|
||||||
version: Constants.vNumber,
|
version: Constants.vNumber,
|
||||||
date: new Date().toISOString().substring(0, 16),
|
date: new Date().toISOString().substring(0, 16),
|
||||||
background: new Translation(bg.properties.name).txt,
|
background: new Translation(bg.properties.name).txt,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Tag } from "../../Logic/Tags/Tag"
|
||||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
|
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
|
||||||
import { Changes } from "../../Logic/Osm/Changes"
|
import { Changes } from "../../Logic/Osm/Changes"
|
||||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||||
import Delete_icon from "../../assets/svg/Delete_icon.svelte"
|
import Delete_icon from "../../assets/svg/Delete_icon.svelte"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ export default class DeleteImage extends Toggle {
|
||||||
constructor(
|
constructor(
|
||||||
key: string,
|
key: string,
|
||||||
tags: Store<any>,
|
tags: Store<any>,
|
||||||
state: { layout: LayoutConfig; changes?: Changes; osmConnection?: OsmConnection }
|
state: { theme: ThemeConfig; changes?: Changes; osmConnection?: OsmConnection }
|
||||||
) {
|
) {
|
||||||
const oldValue = tags.data[key]
|
const oldValue = tags.data[key]
|
||||||
const isDeletedBadge = Translations.t.image.isDeleted
|
const isDeletedBadge = Translations.t.image.isDeleted
|
||||||
|
@ -25,7 +25,7 @@ export default class DeleteImage extends Toggle {
|
||||||
await state?.changes?.applyAction(
|
await state?.changes?.applyAction(
|
||||||
new ChangeTagAction(tags.data.id, new Tag(key, oldValue), tags.data, {
|
new ChangeTagAction(tags.data.id, new Tag(key, oldValue), tags.data, {
|
||||||
changeType: "delete-image",
|
changeType: "delete-image",
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -40,7 +40,7 @@ export default class DeleteImage extends Toggle {
|
||||||
await state?.changes?.applyAction(
|
await state?.changes?.applyAction(
|
||||||
new ChangeTagAction(tags.data.id, new Tag(key, ""), tags.data, {
|
new ChangeTagAction(tags.data.id, new Tag(key, ""), tags.data, {
|
||||||
changeType: "answer",
|
changeType: "answer",
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,7 +7,7 @@ import Toggle from "../Input/Toggle"
|
||||||
import ImageProvider, { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
import ImageProvider, { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
||||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import { Changes } from "../../Logic/Osm/Changes"
|
import { Changes } from "../../Logic/Osm/Changes"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||||
import AttributedImage from "./AttributedImage.svelte"
|
import AttributedImage from "./AttributedImage.svelte"
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ export class ImageCarousel extends Toggle {
|
||||||
state: {
|
state: {
|
||||||
osmConnection?: OsmConnection
|
osmConnection?: OsmConnection
|
||||||
changes?: Changes
|
changes?: Changes
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
previewedImage?: UIEventSource<ProvidedImage>
|
previewedImage?: UIEventSource<ProvidedImage>
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
const url = targetValue
|
const url = targetValue
|
||||||
if (isLinked) {
|
if (isLinked) {
|
||||||
const action = new LinkImageAction(currentTags.id, key, url, tags, {
|
const action = new LinkImageAction(currentTags.id, key, url, tags, {
|
||||||
theme: tags.data._orig_theme ?? state.layout.id,
|
theme: tags.data._orig_theme ?? state.theme.id,
|
||||||
changeType: "link-image"
|
changeType: "link-image"
|
||||||
})
|
})
|
||||||
await state.changes.applyAction(action)
|
await state.changes.applyAction(action)
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
const v = currentTags[k]
|
const v = currentTags[k]
|
||||||
if (v === url) {
|
if (v === url) {
|
||||||
const action = new ChangeTagAction(currentTags.id, new Tag(k, ""), currentTags, {
|
const action = new ChangeTagAction(currentTags.id, new Tag(k, ""), currentTags, {
|
||||||
theme: tags.data._orig_theme ?? state.layout.id,
|
theme: tags.data._orig_theme ?? state.theme.id,
|
||||||
changeType: "remove-image"
|
changeType: "remove-image"
|
||||||
})
|
})
|
||||||
state.changes.applyAction(action)
|
state.changes.applyAction(action)
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
ShowDataLayer.showMultipleLayers(
|
ShowDataLayer.showMultipleLayers(
|
||||||
map,
|
map,
|
||||||
new StaticFeatureSource([feature]),
|
new StaticFeatureSource([feature]),
|
||||||
state.layout.layers,
|
state.theme.layers,
|
||||||
)
|
)
|
||||||
|
|
||||||
onDestroy(
|
onDestroy(
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
const maproulette_id = tags.data[maproulette_id_key] ?? tags.data.mr_taskId ?? tags.data.id
|
const maproulette_id = tags.data[maproulette_id_key] ?? tags.data.mr_taskId ?? tags.data.id
|
||||||
try {
|
try {
|
||||||
await Maproulette.singleton.closeTask(Number(maproulette_id), Number(statusToSet), {
|
await Maproulette.singleton.closeTask(Number(maproulette_id), Number(statusToSet), {
|
||||||
tags: `MapComplete MapComplete:${state.layout.id}`,
|
tags: `MapComplete MapComplete:${state.theme.id}`,
|
||||||
comment: feedback,
|
comment: feedback,
|
||||||
})
|
})
|
||||||
tags.data["mr_taskStatus"] = Maproulette.STATUS_MEANING[Number(statusToSet)]
|
tags.data["mr_taskStatus"] = Maproulette.STATUS_MEANING[Number(statusToSet)]
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
||||||
theme: state.layout?.id ?? "unkown",
|
theme: state.theme?.id ?? "unkown",
|
||||||
changeType: "create",
|
changeType: "create",
|
||||||
snapOnto: snapToWay,
|
snapOnto: snapToWay,
|
||||||
reusePointWithinMeters: 1,
|
reusePointWithinMeters: 1,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import type PresetConfig from "../../../Models/ThemeConfig/PresetConfig"
|
import type PresetConfig from "../../../Models/ThemeConfig/PresetConfig"
|
||||||
import Tr from "../../Base/Tr.svelte"
|
import Tr from "../../Base/Tr.svelte"
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
* This component lists all the presets and allows the user to select one
|
* This component lists all the presets and allows the user to select one
|
||||||
*/
|
*/
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
let layout: LayoutConfig = state.layout
|
let layout: ThemeConfig = state.theme
|
||||||
let presets: {
|
let presets: {
|
||||||
preset: PresetConfig
|
preset: PresetConfig
|
||||||
layer: LayerConfig
|
layer: LayerConfig
|
||||||
|
|
|
@ -10,7 +10,7 @@ import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeature
|
||||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||||
import Loading from "../Base/Loading"
|
import Loading from "../Base/Loading"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Changes } from "../../Logic/Osm/Changes"
|
import { Changes } from "../../Logic/Osm/Changes"
|
||||||
import { UIElement } from "../UIElement"
|
import { UIElement } from "../UIElement"
|
||||||
import FilteredLayer from "../../Models/FilteredLayer"
|
import FilteredLayer from "../../Models/FilteredLayer"
|
||||||
|
@ -32,7 +32,7 @@ export interface AutoAction extends SpecialVisualization {
|
||||||
applyActionOn(
|
applyActionOn(
|
||||||
feature: Feature,
|
feature: Feature,
|
||||||
state: {
|
state: {
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
changes: Changes
|
changes: Changes
|
||||||
indexedFeatures: IndexedFeatureSource
|
indexedFeatures: IndexedFeatureSource
|
||||||
},
|
},
|
||||||
|
@ -282,7 +282,7 @@ export default class AutoApplyButton implements SpecialVisualization {
|
||||||
argument: string[]
|
argument: string[]
|
||||||
): BaseUIElement {
|
): BaseUIElement {
|
||||||
try {
|
try {
|
||||||
if (!state.layout.official && !state.featureSwitchIsTesting.data) {
|
if (!state.theme.official && !state.featureSwitchIsTesting.data) {
|
||||||
const t = Translations.t.general.add.import
|
const t = Translations.t.general.add.import
|
||||||
return new Combine([
|
return new Combine([
|
||||||
new FixedUiElement(
|
new FixedUiElement(
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
featureId,
|
featureId,
|
||||||
deleteConfig.softDeletionTags,
|
deleteConfig.softDeletionTags,
|
||||||
{
|
{
|
||||||
theme: state?.layout?.id ?? "unknown",
|
theme: state?.theme?.id ?? "unknown",
|
||||||
specialMotivation: deleteReason,
|
specialMotivation: deleteReason,
|
||||||
},
|
},
|
||||||
canBeDeleted.data
|
canBeDeleted.data
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
} else {
|
} else {
|
||||||
// no _delete_reason is given, which implies that this is _not_ a deletion but merely a retagging via a nonDeleteMapping
|
// no _delete_reason is given, which implies that this is _not_ a deletion but merely a retagging via a nonDeleteMapping
|
||||||
actionToTake = new ChangeTagAction(featureId, selectedTags, tags.data, {
|
actionToTake = new ChangeTagAction(featureId, selectedTags, tags.data, {
|
||||||
theme: state?.layout?.id ?? "unkown",
|
theme: state?.theme?.id ?? "unkown",
|
||||||
changeType: "special-delete",
|
changeType: "special-delete",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization"
|
import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization"
|
||||||
import { UIEventSource } from "../../../Logic/UIEventSource"
|
import { UIEventSource } from "../../../Logic/UIEventSource"
|
||||||
import { Feature, Geometry, LineString, Polygon } from "geojson"
|
import { Feature, Geometry, LineString, Polygon } from "geojson"
|
||||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
|
||||||
import BaseUIElement from "../../BaseUIElement"
|
import BaseUIElement from "../../BaseUIElement"
|
||||||
import { ImportFlowArguments, ImportFlowUtils } from "./ImportFlow"
|
import { ImportFlowArguments, ImportFlowUtils } from "./ImportFlow"
|
||||||
import Translations from "../../i18n/Translations"
|
import Translations from "../../i18n/Translations"
|
||||||
|
@ -12,7 +11,7 @@ import ConflateImportFlowState from "./ConflateImportFlowState"
|
||||||
import { AutoAction } from "../AutoApplyButton"
|
import { AutoAction } from "../AutoApplyButton"
|
||||||
import { IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
import { IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
||||||
import { Changes } from "../../../Logic/Osm/Changes"
|
import { Changes } from "../../../Logic/Osm/Changes"
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { OsmConnection } from "../../../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../../../Logic/Osm/OsmConnection"
|
||||||
|
|
||||||
export interface ConflateFlowArguments extends ImportFlowArguments {
|
export interface ConflateFlowArguments extends ImportFlowArguments {
|
||||||
|
@ -47,7 +46,7 @@ export default class ConflateImportButtonViz implements SpecialVisualization, Au
|
||||||
feature: Feature<Geometry, { [name: string]: any }>,
|
feature: Feature<Geometry, { [name: string]: any }>,
|
||||||
state: {
|
state: {
|
||||||
osmConnection: OsmConnection
|
osmConnection: OsmConnection
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
changes: Changes
|
changes: Changes
|
||||||
indexedFeatures: IndexedFeatureSource
|
indexedFeatures: IndexedFeatureSource
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { GeoOperations } from "../../../Logic/GeoOperations"
|
||||||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||||
import { MergePointConfig } from "../../../Logic/Osm/Actions/CreateWayWithPointReuseAction"
|
import { MergePointConfig } from "../../../Logic/Osm/Actions/CreateWayWithPointReuseAction"
|
||||||
import { And } from "../../../Logic/Tags/And"
|
import { And } from "../../../Logic/Tags/And"
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Changes } from "../../../Logic/Osm/Changes"
|
import { Changes } from "../../../Logic/Osm/Changes"
|
||||||
import { FeatureSource, IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
import { FeatureSource, IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
||||||
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||||
|
@ -61,7 +61,7 @@ export default class ConflateImportFlowState extends ImportFlow<ConflateFlowArgu
|
||||||
args: ConflateFlowArguments,
|
args: ConflateFlowArguments,
|
||||||
state: {
|
state: {
|
||||||
osmConnection: OsmConnection
|
osmConnection: OsmConnection
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
changes: Changes
|
changes: Changes
|
||||||
indexedFeatures: IndexedFeatureSource
|
indexedFeatures: IndexedFeatureSource
|
||||||
fullNodeDatabase?: FullNodeDatabaseSource
|
fullNodeDatabase?: FullNodeDatabaseSource
|
||||||
|
@ -88,7 +88,7 @@ export default class ConflateImportFlowState extends ImportFlow<ConflateFlowArgu
|
||||||
GeoOperations.removeOvernoding(feature),
|
GeoOperations.removeOvernoding(feature),
|
||||||
idOfFeatureToReplaceGeometry,
|
idOfFeatureToReplaceGeometry,
|
||||||
{
|
{
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
newTags: tagsToApply.data,
|
newTags: tagsToApply.data,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -174,7 +174,7 @@ export default abstract class ImportFlow<ArgT extends ImportFlowArguments> {
|
||||||
return { error: t.hasBeenImported }
|
return { error: t.hasBeenImported }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state.layout.official && !isTesting) {
|
if (!state.theme.official && !isTesting) {
|
||||||
// Unofficial theme - imports not allowed
|
// Unofficial theme - imports not allowed
|
||||||
return {
|
return {
|
||||||
error: t.officialThemesOnly,
|
error: t.officialThemesOnly,
|
||||||
|
@ -183,7 +183,7 @@ export default abstract class ImportFlow<ArgT extends ImportFlowArguments> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.targetLayer === undefined) {
|
if (this.targetLayer === undefined) {
|
||||||
const e = `Target layer not defined: error in import button for theme: ${this.state.layout.id}: layer ${this.args.targetLayer} not found`
|
const e = `Target layer not defined: error in import button for theme: ${this.state.theme.id}: layer ${this.args.targetLayer} not found`
|
||||||
console.error(e)
|
console.error(e)
|
||||||
return { error: new Translation({ "*": e }) }
|
return { error: new Translation({ "*": e }) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// The following variables are used for the map
|
// The following variables are used for the map
|
||||||
const targetLayers: LayerConfig[] = args.targetLayer
|
const targetLayers: LayerConfig[] = args.targetLayer
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.map((tl) => state.layout.layers.find((l) => l.id === tl))
|
.map((tl) => state.theme.layers.find((l) => l.id === tl))
|
||||||
const snapToLayers: string[] | undefined =
|
const snapToLayers: string[] | undefined =
|
||||||
args.snap_onto_layers?.split(",")?.map((l) => l.trim()) ?? []
|
args.snap_onto_layers?.split(",")?.map((l) => l.trim()) ?? []
|
||||||
const maxSnapDistance: number = Number(args.max_snap_distance ?? 25) ?? 25
|
const maxSnapDistance: number = Number(args.max_snap_distance ?? 25) ?? 25
|
||||||
|
|
|
@ -63,7 +63,7 @@ export class PointImportFlowState extends ImportFlow<PointImportFlowArguments> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
||||||
theme: this.state.layout.id,
|
theme: this.state.theme.id,
|
||||||
changeType: "import",
|
changeType: "import",
|
||||||
snapOnto: <OsmWay>snapOnto,
|
snapOnto: <OsmWay>snapOnto,
|
||||||
specialMotivation: specialMotivation,
|
specialMotivation: specialMotivation,
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { FixedUiElement } from "../../Base/FixedUiElement"
|
||||||
import WayImportFlow from "./WayImportFlow.svelte"
|
import WayImportFlow from "./WayImportFlow.svelte"
|
||||||
import WayImportFlowState, { WayImportFlowArguments } from "./WayImportFlowState"
|
import WayImportFlowState, { WayImportFlowArguments } from "./WayImportFlowState"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Changes } from "../../../Logic/Osm/Changes"
|
import { Changes } from "../../../Logic/Osm/Changes"
|
||||||
import { IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
import { IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
||||||
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||||
|
@ -87,7 +87,7 @@ export default class WayImportButtonViz implements AutoAction, SpecialVisualizat
|
||||||
public async applyActionOn(
|
public async applyActionOn(
|
||||||
feature: Feature,
|
feature: Feature,
|
||||||
state: {
|
state: {
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
changes: Changes
|
changes: Changes
|
||||||
indexedFeatures: IndexedFeatureSource
|
indexedFeatures: IndexedFeatureSource
|
||||||
fullNodeDatabase: FullNodeDatabaseSource
|
fullNodeDatabase: FullNodeDatabaseSource
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
ShowDataLayer.showMultipleLayers(
|
ShowDataLayer.showMultipleLayers(
|
||||||
map,
|
map,
|
||||||
new StaticFeatureSource([importFlow.originalFeature]),
|
new StaticFeatureSource([importFlow.originalFeature]),
|
||||||
state.layout.layers,
|
state.theme.layers,
|
||||||
{ zoomToFeatures: false }
|
{ zoomToFeatures: false }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||||
import { OsmCreateAction, PreviewableAction } from "../../../Logic/Osm/Actions/OsmChangeAction"
|
import { OsmCreateAction, PreviewableAction } from "../../../Logic/Osm/Actions/OsmChangeAction"
|
||||||
import { FeatureSource, IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
import { FeatureSource, IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
||||||
import CreateMultiPolygonWithPointReuseAction from "../../../Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction"
|
import CreateMultiPolygonWithPointReuseAction from "../../../Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction"
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Changes } from "../../../Logic/Osm/Changes"
|
import { Changes } from "../../../Logic/Osm/Changes"
|
||||||
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ export default class WayImportFlowState extends ImportFlow<WayImportFlowArgument
|
||||||
feature: Feature<LineString | Polygon>,
|
feature: Feature<LineString | Polygon>,
|
||||||
args: WayImportFlowArguments,
|
args: WayImportFlowArguments,
|
||||||
state: {
|
state: {
|
||||||
layout: LayoutConfig
|
theme: ThemeConfig
|
||||||
changes: Changes
|
changes: Changes
|
||||||
indexedFeatures: IndexedFeatureSource
|
indexedFeatures: IndexedFeatureSource
|
||||||
fullNodeDatabase?: FullNodeDatabaseSource
|
fullNodeDatabase?: FullNodeDatabaseSource
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
} else if (state.changes) {
|
} else if (state.changes) {
|
||||||
await state.changes.applyAction(
|
await state.changes.applyAction(
|
||||||
new ChangeTagAction(tags.data.id, new And(selection), tags.data, {
|
new ChangeTagAction(tags.data.id, new And(selection), tags.data, {
|
||||||
theme: state?.layout?.id ?? "unkown",
|
theme: state?.theme?.id ?? "unkown",
|
||||||
changeType: "answer",
|
changeType: "answer",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
const t = Translations.t.favouritePoi
|
const t = Translations.t.favouritePoi
|
||||||
|
|
||||||
function markFavourite(isFavourite: boolean) {
|
function markFavourite(isFavourite: boolean) {
|
||||||
state.favourites.markAsFavourite(feature, layer.id, state.layout.id, tags, isFavourite)
|
state.favourites.markAsFavourite(feature, layer.id, state.theme.id, tags, isFavourite)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
const t = Translations.t.favouritePoi
|
const t = Translations.t.favouritePoi
|
||||||
|
|
||||||
function markFavourite(isFavourite: boolean) {
|
function markFavourite(isFavourite: boolean) {
|
||||||
state.favourites.markAsFavourite(feature, layer.id, state.layout.id, tags, isFavourite)
|
state.favourites.markAsFavourite(feature, layer.id, state.theme.id, tags, isFavourite)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
ShowDataLayer.showMultipleLayers(
|
ShowDataLayer.showMultipleLayers(
|
||||||
mlmap,
|
mlmap,
|
||||||
new StaticFeatureSource(featuresToShow),
|
new StaticFeatureSource(featuresToShow),
|
||||||
state.layout.layers,
|
state.theme.layers,
|
||||||
{ zoomToFeatures: true }
|
{ zoomToFeatures: true }
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -94,7 +94,7 @@ export class MoveWizardState {
|
||||||
const matchingPresets = this.layer.presets.filter(preset => preset.preciseInput.snapToLayers && new And(preset.tags).matchesProperties(tags))
|
const matchingPresets = this.layer.presets.filter(preset => preset.preciseInput.snapToLayers && new And(preset.tags).matchesProperties(tags))
|
||||||
const matchingPreset = matchingPresets.flatMap(pr => pr.preciseInput?.snapToLayers)
|
const matchingPreset = matchingPresets.flatMap(pr => pr.preciseInput?.snapToLayers)
|
||||||
for (const layerId of matchingPreset) {
|
for (const layerId of matchingPreset) {
|
||||||
const snapOntoLayer = this._state.layout.getLayer(layerId)
|
const snapOntoLayer = this._state.theme.getLayer(layerId)
|
||||||
const text = <Translation> t.reasons.reasonSnapTo.PartialSubsTr("name", snapOntoLayer.snapName)
|
const text = <Translation> t.reasons.reasonSnapTo.PartialSubsTr("name", snapOntoLayer.snapName)
|
||||||
reasons.push({
|
reasons.push({
|
||||||
text,
|
text,
|
||||||
|
@ -133,7 +133,7 @@ export class MoveWizardState {
|
||||||
snappedTo,
|
snappedTo,
|
||||||
{
|
{
|
||||||
reason: reason.changesetCommentValue,
|
reason: reason.changesetCommentValue,
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
featureToMove.properties._lat = loc.lat
|
featureToMove.properties._lat = loc.lat
|
||||||
|
@ -152,7 +152,7 @@ export class MoveWizardState {
|
||||||
featureToMove.properties,
|
featureToMove.properties,
|
||||||
{
|
{
|
||||||
changeType: "relocated",
|
changeType: "relocated",
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -64,7 +64,7 @@ class MultiApplyExecutor {
|
||||||
const keysToChange = this.params.keysToApply
|
const keysToChange = this.params.keysToApply
|
||||||
const overwrite = this.params.overwrite
|
const overwrite = this.params.overwrite
|
||||||
const selfTags = this.params.tagsSource.data
|
const selfTags = this.params.tagsSource.data
|
||||||
const theme = this.params.state.layout.id
|
const theme = this.params.state.theme.id
|
||||||
for (const id of featuresToChange) {
|
for (const id of featuresToChange) {
|
||||||
const tagsToApply: Tag[] = []
|
const tagsToApply: Tag[] = []
|
||||||
const otherFeatureTags = allElements.getStore(id).data
|
const otherFeatureTags = allElements.getStore(id).data
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const loc = coordinate.data
|
const loc = coordinate.data
|
||||||
txt += "\n\n #MapComplete #" + state?.layout?.id
|
txt += "\n\n #MapComplete #" + state?.theme?.id
|
||||||
const id = await state?.osmConnection?.openNote(loc.lat, loc.lon, txt)
|
const id = await state?.osmConnection?.openNote(loc.lat, loc.lon, txt)
|
||||||
console.log("Created a note, got id", id)
|
console.log("Created a note, got id", id)
|
||||||
const feature = <Feature<Point, OsmTags>>{
|
const feature = <Feature<Point, OsmTags>>{
|
||||||
|
|
|
@ -49,7 +49,7 @@ export class PlantNetDetectionViz implements SpecialVisualization {
|
||||||
]),
|
]),
|
||||||
tags.data,
|
tags.data,
|
||||||
{
|
{
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
changeType: "plantnet-ai-detection",
|
changeType: "plantnet-ai-detection",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
let [lon, lat] = GeoOperations.centerpointCoordinates(feature)
|
let [lon, lat] = GeoOperations.centerpointCoordinates(feature)
|
||||||
|
|
||||||
const includeLayout = window.location.pathname.split("/").at(-1).startsWith("theme")
|
const includeLayout = window.location.pathname.split("/").at(-1).startsWith("theme")
|
||||||
const layout = includeLayout ? "layout=" + state.layout.id + "&" : ""
|
const layout = includeLayout ? "layout=" + state.theme.id + "&" : ""
|
||||||
let id: Store<string> = tags.mapD((tags) => tags.id)
|
let id: Store<string> = tags.mapD((tags) => tags.id)
|
||||||
let url = id.mapD(
|
let url = id.mapD(
|
||||||
(id) =>
|
(id) =>
|
||||||
|
|
|
@ -30,9 +30,9 @@ export class ShareLinkViz implements SpecialVisualization {
|
||||||
const text = args[1]
|
const text = args[1]
|
||||||
|
|
||||||
const generateShareData = () => {
|
const generateShareData = () => {
|
||||||
const title = state?.layout?.title?.txt ?? "MapComplete"
|
const title = state?.theme?.title?.txt ?? "MapComplete"
|
||||||
|
|
||||||
let matchingLayer: LayerConfig = state?.layout?.getMatchingLayer(tagSource?.data)
|
let matchingLayer: LayerConfig = state?.theme?.getMatchingLayer(tagSource?.data)
|
||||||
let name =
|
let name =
|
||||||
matchingLayer?.title?.GetRenderValue(tagSource.data)?.Subs(tagSource.data)?.txt ??
|
matchingLayer?.title?.GetRenderValue(tagSource.data)?.Subs(tagSource.data)?.txt ??
|
||||||
tagSource.data?.name ??
|
tagSource.data?.name ??
|
||||||
|
@ -49,7 +49,7 @@ export class ShareLinkViz implements SpecialVisualization {
|
||||||
return {
|
return {
|
||||||
title: name,
|
title: name,
|
||||||
url: url,
|
url: url,
|
||||||
text: state?.layout?.shortDescription?.txt ?? "MapComplete",
|
text: state?.theme?.shortDescription?.txt ?? "MapComplete",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
id,
|
id,
|
||||||
splitPoints.data.map((ff) => <[number, number]>(<Point>ff.geometry).coordinates),
|
splitPoints.data.map((ff) => <[number, number]>(<Point>ff.geometry).coordinates),
|
||||||
{
|
{
|
||||||
theme: state?.layout?.id,
|
theme: state?.theme?.id,
|
||||||
},
|
},
|
||||||
5
|
5
|
||||||
)
|
)
|
||||||
|
|
|
@ -144,7 +144,7 @@ export default class TagApplyButton implements AutoAction, SpecialVisualization
|
||||||
new And(tagsToApply.data),
|
new And(tagsToApply.data),
|
||||||
tags.data, // We pass in the tags of the selected element, not the tags of the target element!
|
tags.data, // We pass in the tags of the selected element, not the tags of the target element!
|
||||||
{
|
{
|
||||||
theme: state.layout.id,
|
theme: state.theme.id,
|
||||||
changeType: "answer",
|
changeType: "answer",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -283,7 +283,7 @@
|
||||||
}
|
}
|
||||||
dispatch("saved", { config, applied: selectedTags })
|
dispatch("saved", { config, applied: selectedTags })
|
||||||
const change = new ChangeTagAction(tags.data.id, selectedTags, tags.data, {
|
const change = new ChangeTagAction(tags.data.id, selectedTags, tags.data, {
|
||||||
theme: tags.data["_orig_theme"] ?? state.layout.id,
|
theme: tags.data["_orig_theme"] ?? state.theme.id,
|
||||||
changeType: "answer",
|
changeType: "answer",
|
||||||
})
|
})
|
||||||
freeformInput.set(undefined)
|
freeformInput.set(undefined)
|
||||||
|
@ -327,7 +327,7 @@
|
||||||
function clearAnswer() {
|
function clearAnswer() {
|
||||||
const tagsToSet = settableKeys.data.map(k => new Tag(k, ""))
|
const tagsToSet = settableKeys.data.map(k => new Tag(k, ""))
|
||||||
const change = new ChangeTagAction(tags.data.id, new And(tagsToSet), tags.data, {
|
const change = new ChangeTagAction(tags.data.id, new And(tagsToSet), tags.data, {
|
||||||
theme: tags.data["_orig_theme"] ?? state.layout.id,
|
theme: tags.data["_orig_theme"] ?? state.theme.id,
|
||||||
changeType: "answer",
|
changeType: "answer",
|
||||||
})
|
})
|
||||||
freeformInput.set(undefined)
|
freeformInput.set(undefined)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import List from "./Base/List"
|
||||||
import Translations from "./i18n/Translations"
|
import Translations from "./i18n/Translations"
|
||||||
import { QueryParameters } from "../Logic/Web/QueryParameters"
|
import { QueryParameters } from "../Logic/Web/QueryParameters"
|
||||||
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
|
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
|
||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||||
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
||||||
import MarkdownUtils from "../Utils/MarkdownUtils"
|
import MarkdownUtils from "../Utils/MarkdownUtils"
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ export default class QueryParameterDocumentation {
|
||||||
]
|
]
|
||||||
|
|
||||||
public static UrlParamDocs(): Map<string, string> {
|
public static UrlParamDocs(): Map<string, string> {
|
||||||
const dummyLayout = new LayoutConfig(<any>{
|
const dummyLayout = new ThemeConfig(<any>{
|
||||||
id: ">theme<",
|
id: ">theme<",
|
||||||
title: { en: "<theme>" },
|
title: { en: "<theme>" },
|
||||||
description: "A theme to generate docs with",
|
description: "A theme to generate docs with",
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
let tags: UIEventSource<Record<string, string>>
|
let tags: UIEventSource<Record<string, string>>
|
||||||
let descriptionTr: TagRenderingConfig = undefined
|
let descriptionTr: TagRenderingConfig = undefined
|
||||||
if (entry.feature?.properties?.id) {
|
if (entry.feature?.properties?.id) {
|
||||||
layer = state.layout.getMatchingLayer(entry.feature.properties)
|
layer = state.theme.getMatchingLayer(entry.feature.properties)
|
||||||
tags = state.featureProperties.getStore(entry.feature.properties.id)
|
tags = state.featureProperties.getStore(entry.feature.properties.id)
|
||||||
descriptionTr = layer?.tagRenderings?.find(tr => tr.labels.indexOf("description") >= 0)
|
descriptionTr = layer?.tagRenderings?.find(tr => tr.labels.indexOf("description") >= 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Translation } from "../i18n/Translation"
|
import { Translation } from "../i18n/Translation"
|
||||||
import Icon from "../Map/Icon.svelte"
|
import Icon from "../Map/Icon.svelte"
|
||||||
import Tr from "../Base/Tr.svelte"
|
import Tr from "../Base/Tr.svelte"
|
||||||
import ThemeSearch from "../../Logic/Search/ThemeSearch"
|
import ThemeSearch from "../../Logic/Search/ThemeSearch"
|
||||||
|
|
||||||
export let entry: MinimalLayoutInformation
|
export let entry: MinimalThemeInformation
|
||||||
let otherTheme = entry
|
let otherTheme = entry
|
||||||
</script>
|
</script>
|
||||||
{#if entry}
|
{#if entry}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
let searchTerm = state.searchState.searchTerm
|
let searchTerm = state.searchState.searchTerm
|
||||||
let recentThemes = state.userRelatedState.recentlyVisitedThemes.value.map(themes => themes.filter(th => th !== state.layout.id).slice(0, 6))
|
let recentThemes = state.userRelatedState.recentlyVisitedThemes.value.map(themes => themes.filter(th => th !== state.theme.id).slice(0, 6))
|
||||||
let themeResults = state.searchState.themeSuggestions
|
let themeResults = state.searchState.themeSuggestions
|
||||||
|
|
||||||
const t =Translations.t.general.search
|
const t =Translations.t.general.search
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||||
import BaseUIElement from "./BaseUIElement"
|
import BaseUIElement from "./BaseUIElement"
|
||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||||
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 { Changes } from "../Logic/Osm/Changes"
|
import { Changes } from "../Logic/Osm/Changes"
|
||||||
|
@ -19,7 +19,7 @@ import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFe
|
||||||
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
|
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
|
||||||
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
|
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
|
||||||
import { SummaryTileSourceRewriter } from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
|
import { SummaryTileSourceRewriter } from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
|
||||||
import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource"
|
import ThemeSource from "../Logic/FeatureSource/Sources/ThemeSource"
|
||||||
import { Map as MlMap } from "maplibre-gl"
|
import { Map as MlMap } from "maplibre-gl"
|
||||||
import ShowDataLayer from "./Map/ShowDataLayer"
|
import ShowDataLayer from "./Map/ShowDataLayer"
|
||||||
import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch"
|
import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch"
|
||||||
|
@ -33,13 +33,13 @@ import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropert
|
||||||
*/
|
*/
|
||||||
export interface SpecialVisualizationState {
|
export interface SpecialVisualizationState {
|
||||||
readonly guistate: MenuState
|
readonly guistate: MenuState
|
||||||
readonly layout: LayoutConfig
|
readonly theme: ThemeConfig
|
||||||
readonly featureSwitches: FeatureSwitchState
|
readonly featureSwitches: FeatureSwitchState
|
||||||
|
|
||||||
readonly layerState: LayerState
|
readonly layerState: LayerState
|
||||||
readonly featureProperties: FeaturePropertiesStore
|
readonly featureProperties: FeaturePropertiesStore
|
||||||
|
|
||||||
readonly indexedFeatures: IndexedFeatureSource & LayoutSource
|
readonly indexedFeatures: IndexedFeatureSource & ThemeSource
|
||||||
/**
|
/**
|
||||||
* Some features will create a new element that should be displayed.
|
* Some features will create a new element that should be displayed.
|
||||||
* These can be injected by appending them to this featuresource (and pinging it)
|
* These can be injected by appending them to this featuresource (and pinging it)
|
||||||
|
|
|
@ -164,7 +164,7 @@ class StealViz implements SpecialVisualization {
|
||||||
const tagRenderings: [LayerConfig, TagRenderingConfig][] = []
|
const tagRenderings: [LayerConfig, TagRenderingConfig][] = []
|
||||||
for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) {
|
for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) {
|
||||||
const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".")
|
const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".")
|
||||||
const layer = state.layout.layers.find((l) => l.id === layerId)
|
const layer = state.theme.layers.find((l) => l.id === layerId)
|
||||||
const tagRendering = layer.tagRenderings.find((tr) => tr.id === tagRenderingId)
|
const tagRendering = layer.tagRenderings.find((tr) => tr.id === tagRenderingId)
|
||||||
tagRenderings.push([layer, tagRendering])
|
tagRenderings.push([layer, tagRendering])
|
||||||
}
|
}
|
||||||
|
@ -444,7 +444,7 @@ export default class SpecialVisualizations {
|
||||||
Locale.showLinkToWeblate.map((showTranslations) => {
|
Locale.showLinkToWeblate.map((showTranslations) => {
|
||||||
const languages = showTranslations
|
const languages = showTranslations
|
||||||
? LanguageUtils.usedLanguagesSorted
|
? LanguageUtils.usedLanguagesSorted
|
||||||
: state.layout.language
|
: state.theme.language
|
||||||
return new SvelteUIElement(LanguagePicker, {
|
return new SvelteUIElement(LanguagePicker, {
|
||||||
assignTo: state.userRelatedState.language,
|
assignTo: state.userRelatedState.language,
|
||||||
availableLanguages: languages,
|
availableLanguages: languages,
|
||||||
|
@ -971,7 +971,7 @@ export default class SpecialVisualizations {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
const allUnits: Unit[] = [].concat(
|
const allUnits: Unit[] = [].concat(
|
||||||
...(state?.layout?.layers?.map((lyr) => lyr.units) ?? [])
|
...(state?.theme?.layers?.map((lyr) => lyr.units) ?? [])
|
||||||
)
|
)
|
||||||
const unit = allUnits.filter((unit) =>
|
const unit = allUnits.filter((unit) =>
|
||||||
unit.isApplicableToKey(key)
|
unit.isApplicableToKey(key)
|
||||||
|
@ -1125,7 +1125,7 @@ export default class SpecialVisualizations {
|
||||||
) =>
|
) =>
|
||||||
new VariableUiElement(
|
new VariableUiElement(
|
||||||
tagsSource.map((tags) => {
|
tagsSource.map((tags) => {
|
||||||
if (state.layout === undefined) {
|
if (state.theme === undefined) {
|
||||||
return "<feature title>"
|
return "<feature title>"
|
||||||
}
|
}
|
||||||
const title = layer?.title?.GetRenderValue(tags)
|
const title = layer?.title?.GetRenderValue(tags)
|
||||||
|
@ -1276,7 +1276,7 @@ export default class SpecialVisualizations {
|
||||||
|
|
||||||
constr: (state) => {
|
constr: (state) => {
|
||||||
return new Combine(
|
return new Combine(
|
||||||
state.layout.layers
|
state.theme.layers
|
||||||
.filter(
|
.filter(
|
||||||
(l) =>
|
(l) =>
|
||||||
l.name !== null &&
|
l.name !== null &&
|
||||||
|
@ -1995,7 +1995,7 @@ export default class SpecialVisualizations {
|
||||||
layer: LayerConfig
|
layer: LayerConfig
|
||||||
): BaseUIElement {
|
): BaseUIElement {
|
||||||
const translation = tagSource.map((tags) => {
|
const translation = tagSource.map((tags) => {
|
||||||
const layer = state.layout.getMatchingLayer(tags)
|
const layer = state.theme.getMatchingLayer(tags)
|
||||||
return layer?.getMostMatchingPreset(tags)?.description
|
return layer?.getMostMatchingPreset(tags)?.description
|
||||||
})
|
})
|
||||||
return new VariableUiElement(translation)
|
return new VariableUiElement(translation)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import BaseUIElement from "./BaseUIElement"
|
||||||
import Title from "./Base/Title"
|
import Title from "./Base/Title"
|
||||||
import { FixedUiElement } from "./Base/FixedUiElement"
|
import { FixedUiElement } from "./Base/FixedUiElement"
|
||||||
import List from "./Base/List"
|
import List from "./Base/List"
|
||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||||
import mcChanges from "../../src/assets/generated/themes/mapcomplete-changes.json"
|
import mcChanges from "../../src/assets/generated/themes/mapcomplete-changes.json"
|
||||||
import SvelteUIElement from "./Base/SvelteUIElement"
|
import SvelteUIElement from "./Base/SvelteUIElement"
|
||||||
import Filterview from "./BigComponents/Filterview.svelte"
|
import Filterview from "./BigComponents/Filterview.svelte"
|
||||||
|
@ -24,7 +24,7 @@ import { Feature } from "geojson"
|
||||||
class StatsticsForOverviewFile extends Combine {
|
class StatsticsForOverviewFile extends Combine {
|
||||||
constructor(homeUrl: string, paths: string[]) {
|
constructor(homeUrl: string, paths: string[]) {
|
||||||
paths = paths.filter((p) => !p.endsWith("file-overview.json"))
|
paths = paths.filter((p) => !p.endsWith("file-overview.json"))
|
||||||
const layer = new LayoutConfig(<any>mcChanges, true).layers[0]
|
const layer = new ThemeConfig(<any>mcChanges, true).layers[0]
|
||||||
const filteredLayer = new FilteredLayer(layer)
|
const filteredLayer = new FilteredLayer(layer)
|
||||||
const filterPanel = new Combine([
|
const filterPanel = new Combine([
|
||||||
new Title("Filters"),
|
new Title("Filters"),
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import { OsmTags } from "../../Models/OsmFeature"
|
import { OsmTags } from "../../Models/OsmFeature"
|
||||||
import { Feature, Point } from "geojson"
|
import { Feature, Point } from "geojson"
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
import { LayoutConfigJson } from "../../Models/ThemeConfig/Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../../Models/ThemeConfig/Json/ThemeConfigJson"
|
||||||
import { PrepareTheme } from "../../Models/ThemeConfig/Conversion/PrepareTheme"
|
import { PrepareTheme } from "../../Models/ThemeConfig/Conversion/PrepareTheme"
|
||||||
import { ConversionContext } from "../../Models/ThemeConfig/Conversion/ConversionContext"
|
import { ConversionContext } from "../../Models/ThemeConfig/Conversion/ConversionContext"
|
||||||
import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource"
|
import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource"
|
||||||
|
@ -334,7 +334,7 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public readonly layout: { getMatchingLayer: (key: any) => LayerConfig }
|
public readonly theme: { getMatchingLayer: (key: any) => LayerConfig }
|
||||||
public readonly featureSwitches: {
|
public readonly featureSwitches: {
|
||||||
featureSwitchIsDebugging: UIEventSource<boolean>
|
featureSwitchIsDebugging: UIEventSource<boolean>
|
||||||
}
|
}
|
||||||
|
@ -359,7 +359,7 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
|
||||||
options: { expertMode: UIEventSource<boolean> }
|
options: { expertMode: UIEventSource<boolean> }
|
||||||
) {
|
) {
|
||||||
super(schema, server, "layers", osmConnection, options)
|
super(schema, server, "layers", osmConnection, options)
|
||||||
this.layout = {
|
this.theme = {
|
||||||
getMatchingLayer: () => {
|
getMatchingLayer: () => {
|
||||||
try {
|
try {
|
||||||
return new LayerConfig(<LayerConfigJson>this.configuration.data, "dynamic")
|
return new LayerConfig(<LayerConfigJson>this.configuration.data, "dynamic")
|
||||||
|
@ -458,7 +458,8 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
|
||||||
}
|
}
|
||||||
const state: DesugaringContext = {
|
const state: DesugaringContext = {
|
||||||
tagRenderings: sharedQuestions,
|
tagRenderings: sharedQuestions,
|
||||||
sharedLayers: layers
|
sharedLayers: layers,
|
||||||
|
tagRenderingOrder: []
|
||||||
}
|
}
|
||||||
const prepare = this.buildValidation(state)
|
const prepare = this.buildValidation(state)
|
||||||
const context = ConversionContext.construct([], ["prepare"])
|
const context = ConversionContext.construct([], ["prepare"])
|
||||||
|
@ -472,7 +473,7 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EditThemeState extends EditJsonState<LayoutConfigJson> {
|
export class EditThemeState extends EditJsonState<ThemeConfigJson> {
|
||||||
constructor(
|
constructor(
|
||||||
schema: ConfigMeta[],
|
schema: ConfigMeta[],
|
||||||
server: StudioServer,
|
server: StudioServer,
|
||||||
|
@ -483,7 +484,7 @@ export class EditThemeState extends EditJsonState<LayoutConfigJson> {
|
||||||
this.setupFixers()
|
this.setupFixers()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected buildValidation(state: DesugaringContext): Conversion<LayoutConfigJson, any> {
|
protected buildValidation(state: DesugaringContext): Conversion<ThemeConfigJson, any> {
|
||||||
return new Pipe(
|
return new Pipe(
|
||||||
new PrevalidateTheme(),
|
new PrevalidateTheme(),
|
||||||
new Pipe(
|
new Pipe(
|
||||||
|
@ -513,7 +514,7 @@ export class EditThemeState extends EditJsonState<LayoutConfigJson> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async validate(configuration: Partial<LayoutConfigJson>) {
|
protected async validate(configuration: Partial<ThemeConfigJson>) {
|
||||||
const layers = AllSharedLayers.getSharedLayersConfigs()
|
const layers = AllSharedLayers.getSharedLayersConfigs()
|
||||||
|
|
||||||
for (const l of configuration.layers ?? []) {
|
for (const l of configuration.layers ?? []) {
|
||||||
|
@ -534,7 +535,8 @@ export class EditThemeState extends EditJsonState<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
const state: DesugaringContext = {
|
const state: DesugaringContext = {
|
||||||
tagRenderings: sharedQuestions,
|
tagRenderings: sharedQuestions,
|
||||||
sharedLayers: layers
|
sharedLayers: layers,
|
||||||
|
tagRenderingOrder: []
|
||||||
}
|
}
|
||||||
const prepare = this.buildValidation(state)
|
const prepare = this.buildValidation(state)
|
||||||
const context = ConversionContext.construct([], ["prepare"])
|
const context = ConversionContext.construct([], ["prepare"])
|
||||||
|
@ -542,7 +544,7 @@ export class EditThemeState extends EditJsonState<LayoutConfigJson> {
|
||||||
Utils.NoNullInplace(configuration.layers)
|
Utils.NoNullInplace(configuration.layers)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
prepare.convert(<LayoutConfigJson>configuration, context)
|
prepare.convert(<ThemeConfigJson>configuration, context)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
context.err(e)
|
context.err(e)
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Utils } from "../../Utils"
|
||||||
import Constants from "../../Models/Constants"
|
import Constants from "../../Models/Constants"
|
||||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import { LayoutConfigJson } from "../../Models/ThemeConfig/Json/LayoutConfigJson"
|
import { ThemeConfigJson } from "../../Models/ThemeConfig/Json/ThemeConfigJson"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A small class wrapping around the Server API.
|
* A small class wrapping around the Server API.
|
||||||
|
@ -71,12 +71,12 @@ export default class StudioServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetch(layerId: string, category: "layers", uid?: number): Promise<LayerConfigJson>
|
async fetch(layerId: string, category: "layers", uid?: number): Promise<LayerConfigJson>
|
||||||
async fetch(layerId: string, category: "themes", uid?: number): Promise<LayoutConfigJson>
|
async fetch(layerId: string, category: "themes", uid?: number): Promise<ThemeConfigJson>
|
||||||
async fetch(
|
async fetch(
|
||||||
layerId: string,
|
layerId: string,
|
||||||
category: "layers" | "themes",
|
category: "layers" | "themes",
|
||||||
uid?: number
|
uid?: number
|
||||||
): Promise<LayerConfigJson | LayoutConfigJson> {
|
): Promise<LayerConfigJson | ThemeConfigJson> {
|
||||||
try {
|
try {
|
||||||
return <any>await Utils.downloadJson(this.urlFor(layerId, category, uid))
|
return <any>await Utils.downloadJson(this.urlFor(layerId, category, uid))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
export let state: ThemeViewState
|
export let state: ThemeViewState
|
||||||
|
|
||||||
|
|
||||||
let layout = state.layout
|
let theme = state.theme
|
||||||
let maplibremap: UIEventSource<MlMap> = state.map
|
let maplibremap: UIEventSource<MlMap> = state.map
|
||||||
let state_selectedElement = state.selectedElement
|
let state_selectedElement = state.selectedElement
|
||||||
let selectedElement: UIEventSource<Feature> = new UIEventSource<Feature>(undefined)
|
let selectedElement: UIEventSource<Feature> = new UIEventSource<Feature>(undefined)
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
let gpsButtonAriaLabel = state.geolocation.geolocationState.gpsStateExplanation
|
let gpsButtonAriaLabel = state.geolocation.geolocationState.gpsStateExplanation
|
||||||
let debug = state.featureSwitches.featureSwitchIsDebugging
|
let debug = state.featureSwitches.featureSwitchIsDebugging
|
||||||
let featureSwitches: FeatureSwitchState = state.featureSwitches
|
let featureSwitches: FeatureSwitchState = state.featureSwitches
|
||||||
let currentViewLayer: LayerConfig = layout.layers.find((l) => l.id === "current_view")
|
let currentViewLayer: LayerConfig = theme.layers.find((l) => l.id === "current_view")
|
||||||
let rasterLayer: Store<RasterLayerPolygon> = state.mapProperties.rasterLayer
|
let rasterLayer: Store<RasterLayerPolygon> = state.mapProperties.rasterLayer
|
||||||
let currentZoom = state.mapProperties.zoom
|
let currentZoom = state.mapProperties.zoom
|
||||||
let showCrosshair = state.userRelatedState.showCrosshair
|
let showCrosshair = state.userRelatedState.showCrosshair
|
||||||
|
@ -213,7 +213,7 @@
|
||||||
<div class="flex w-full items-end justify-between px-4">
|
<div class="flex w-full items-end justify-between px-4">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<If condition={featureSwitches.featureSwitchEnableLogin}>
|
<If condition={featureSwitches.featureSwitchEnableLogin}>
|
||||||
{#if $addNewFeatureMode.indexOf("button") >= 0 && ((state.layout.hasPresets() && state.layout.enableAddNewPoints) || state.layout.hasNoteLayer())}
|
{#if $addNewFeatureMode.indexOf("button") >= 0 && ((state.theme.hasPresets() && state.theme.enableAddNewPoints) || state.theme.hasNoteLayer())}
|
||||||
<button
|
<button
|
||||||
class="low-interaction pointer-events-auto w-fit"
|
class="low-interaction pointer-events-auto w-fit"
|
||||||
class:disabled={$currentZoom < Constants.minZoomLevelToAddNewPoint}
|
class:disabled={$currentZoom < Constants.minZoomLevelToAddNewPoint}
|
||||||
|
@ -224,7 +224,7 @@
|
||||||
>
|
>
|
||||||
{#if $currentZoom < Constants.minZoomLevelToAddNewPoint}
|
{#if $currentZoom < Constants.minZoomLevelToAddNewPoint}
|
||||||
<Tr t={Translations.t.general.add.zoomInFurther} />
|
<Tr t={Translations.t.general.add.zoomInFurther} />
|
||||||
{:else if state.layout.hasPresets()}
|
{:else if state.theme.hasPresets()}
|
||||||
✨ <Tr t={Translations.t.general.add.title} />
|
✨ <Tr t={Translations.t.general.add.title} />
|
||||||
{:else}
|
{:else}
|
||||||
<Tr t={Translations.t.notes.addAComment} />
|
<Tr t={Translations.t.notes.addAComment} />
|
||||||
|
@ -351,9 +351,9 @@
|
||||||
<div
|
<div
|
||||||
class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 mr-2"
|
class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 mr-2"
|
||||||
>
|
>
|
||||||
<Marker icons={layout.icon} size="h-6 w-6 shrink-0 mr-0.5 sm:mr-1 md:mr-2" />
|
<Marker icons={theme.icon} size="h-6 w-6 shrink-0 mr-0.5 sm:mr-1 md:mr-2" />
|
||||||
<b class="mr-1">
|
<b class="mr-1">
|
||||||
<Tr t={layout.title} />
|
<Tr t={theme.title} />
|
||||||
</b>
|
</b>
|
||||||
</div>
|
</div>
|
||||||
</MapControlButton>
|
</MapControlButton>
|
||||||
|
|
|
@ -52,7 +52,7 @@ export class PngMapCreator {
|
||||||
|
|
||||||
PngMapCreator.id++
|
PngMapCreator.id++
|
||||||
try {
|
try {
|
||||||
const layout = this._state.layout
|
const layout = this._state.theme
|
||||||
|
|
||||||
function setState(msg: string) {
|
function setState(msg: string) {
|
||||||
status?.setData(layout.id + ": " + msg)
|
status?.setData(layout.id + ": " + msg)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { QueryParameters } from "./Logic/Web/QueryParameters"
|
import { QueryParameters } from "./Logic/Web/QueryParameters"
|
||||||
import AllThemesGui from "./UI/AllThemesGui.svelte"
|
import AllThemesGui from "./UI/AllThemesGui.svelte"
|
||||||
|
|
||||||
const layout = QueryParameters.GetQueryParameter("layout", undefined).data ?? ""
|
const theme = QueryParameters.GetQueryParameter("layout", undefined).data ?? ""
|
||||||
const customLayout = QueryParameters.GetQueryParameter("userlayout", undefined).data ?? ""
|
const customLayout = QueryParameters.GetQueryParameter("userlayout", undefined).data ?? ""
|
||||||
const l = window.location
|
const l = window.location
|
||||||
if (layout !== "") {
|
if (theme !== "") {
|
||||||
if (window.location.host.startsWith("127.0.0.1")) {
|
if (window.location.host.startsWith("127.0.0.1")) {
|
||||||
window.location.replace(
|
window.location.replace(
|
||||||
l.protocol +
|
l.protocol +
|
||||||
|
@ -13,12 +13,12 @@ if (layout !== "") {
|
||||||
"/theme.html" +
|
"/theme.html" +
|
||||||
l.search +
|
l.search +
|
||||||
"&layout=" +
|
"&layout=" +
|
||||||
layout +
|
theme +
|
||||||
l.hash
|
l.hash
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
window.location.replace(
|
window.location.replace(
|
||||||
l.protocol + "//" + window.location.host + "/" + layout + ".html" + l.search + l.hash
|
l.protocol + "//" + window.location.host + "/" + theme + ".html" + l.search + l.hash
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if (customLayout !== "") {
|
} else if (customLayout !== "") {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue