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?
|
||||
---------------------
|
||||
|
||||
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**.
|
||||
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:
|
||||
|
||||
- [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)
|
||||
- [The `TagRendering`](/src/Models/ThemeConfig/Json/TagRenderingConfigJson.ts)
|
||||
- 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
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
"minzoom": 18,
|
||||
"isCounted": false,
|
||||
"calculatedTags": [
|
||||
"_surface:strict:=feat(get)('_surface')"
|
||||
"_surface:strict:=get(feat)('_surface')"
|
||||
],
|
||||
"tagRenderings": [
|
||||
{
|
||||
|
@ -224,19 +224,19 @@
|
|||
"minzoom": 18,
|
||||
"calculatedTags": [
|
||||
"_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_properties=feat(get)('_overlaps_with')?.feat?.properties",
|
||||
"_overlap_percentage=Math.round(100 * (feat(get)('_overlaps_with')?.overlap / feat(get)('_overlaps_with_properties')['_surface:strict']))",
|
||||
"_reverse_overlap_percentage=Math.round(100 * (feat(get)('_overlaps_with')?.overlap / feat(get)('_surface')))",
|
||||
"_overlaps_with=get(feat)('_overlaps_with_buildings').find(f => f.overlap > 1 /* square meter */ )",
|
||||
"_overlaps_with_properties=get(feat)('_overlaps_with')?.feat?.properties",
|
||||
"_overlap_percentage=Math.round(100 * (get(feat)('_overlaps_with')?.overlap / get(feat)('_overlaps_with_properties')['_surface:strict']))",
|
||||
"_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: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:ref:bag=Number(feat.properties.identificatie)",
|
||||
"_bag_obj:source:date=new Date().toISOString().split('T')[0]",
|
||||
"_bag_obj:start_date=feat.properties.bouwjaar",
|
||||
"_osm_obj:id=feat(get)('_overlaps_with_properties')?.id",
|
||||
"_osm_obj:building=feat(get)('_overlaps_with_properties')?.building",
|
||||
"_imported_osm_object_found:=Number(feat.properties.identificatie)==Number(feat(get)('_overlaps_with_properties')['ref:bag'])"
|
||||
"_osm_obj:id=get(feat)('_overlaps_with_properties')?.id",
|
||||
"_osm_obj:building=get(feat)('_overlaps_with_properties')?.building",
|
||||
"_imported_osm_object_found:=Number(feat.properties.identificatie)==Number(get(feat)('_overlaps_with_properties')['ref:bag'])"
|
||||
],
|
||||
"tagRenderings": [
|
||||
{
|
||||
|
@ -435,11 +435,11 @@
|
|||
"_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:source:date=new Date().toISOString().split('T')[0]",
|
||||
"_osm_obj:addr:city:=feat(get)('_closed_osm_addr')['addr:city']",
|
||||
"_osm_obj:addr:housenumber:=feat(get)('_closed_osm_addr')['addr:housenumber']",
|
||||
"_osm_obj:addr:postcode:=feat(get)('_closed_osm_addr')['addr:postcode']",
|
||||
"_osm_obj:addr:street:=feat(get)('_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'])"
|
||||
"_osm_obj:addr:city:=get(feat)('_closed_osm_addr')['addr:city']",
|
||||
"_osm_obj:addr:housenumber:=get(feat)('_closed_osm_addr')['addr:housenumber']",
|
||||
"_osm_obj:addr:postcode:=get(feat)('_closed_osm_addr')['addr:postcode']",
|
||||
"_osm_obj:addr:street:=get(feat)('_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": [
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as fs from "fs"
|
|||
import { existsSync, lstatSync, readdirSync, readFileSync } from "fs"
|
||||
import { Utils } from "../src/Utils"
|
||||
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 xml2js from "xml2js"
|
||||
|
||||
|
@ -111,7 +111,7 @@ export default class ScriptUtils {
|
|||
}
|
||||
|
||||
public static getThemeFiles(useTranslationPaths = false): {
|
||||
parsed: LayoutConfigJson;
|
||||
parsed: ThemeConfigJson;
|
||||
path: string;
|
||||
raw: string
|
||||
}[] {
|
||||
|
|
|
@ -8,7 +8,7 @@ import QueryParameterDocumentation from "../src/UI/QueryParameterDocumentation"
|
|||
import ScriptUtils from "./ScriptUtils"
|
||||
import Translations from "../src/UI/i18n/Translations"
|
||||
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 fakedom from "fake-dom"
|
||||
import unit from "../src/assets/generated/layers/unit.json"
|
||||
|
@ -253,7 +253,7 @@ export class GenerateDocs extends Script {
|
|||
}
|
||||
|
||||
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(), [
|
||||
"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 layersToShow = theme.layers.filter(
|
||||
(l) =>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import ScriptUtils from "./ScriptUtils"
|
||||
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs"
|
||||
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 Constants from "../src/Models/Constants"
|
||||
import {
|
||||
|
@ -29,7 +29,7 @@ import LayerConfig from "../src/Models/ThemeConfig/LayerConfig"
|
|||
import PointRenderingConfig from "../src/Models/ThemeConfig/PointRenderingConfig"
|
||||
import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/ConversionContext"
|
||||
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 { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
|
||||
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
||||
|
@ -148,14 +148,14 @@ class LayerOverviewUtils extends Script {
|
|||
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))
|
||||
|
||||
return new Set([].concat(...publicThemes.map((th) => this.extractLayerIdsFrom(th))))
|
||||
}
|
||||
|
||||
private static extractLayerIdsFrom(
|
||||
themeFile: LayoutConfigJson,
|
||||
themeFile: ThemeConfigJson,
|
||||
includeInlineLayers = true,
|
||||
): string[] {
|
||||
const publicLayerIds: string[] = []
|
||||
|
@ -295,7 +295,7 @@ class LayerOverviewUtils extends Script {
|
|||
layerKeywords[id] = this.layerKeywords(layer)
|
||||
})
|
||||
|
||||
const perId = new Map<string, MinimalLayoutInformation>()
|
||||
const perId = new Map<string, MinimalThemeInformation>()
|
||||
for (const theme of themes) {
|
||||
|
||||
const keywords: Record<string, string[]> = {}
|
||||
|
@ -308,7 +308,7 @@ class LayerOverviewUtils extends Script {
|
|||
|
||||
}
|
||||
|
||||
const data = <MinimalLayoutInformation> {
|
||||
const data = <MinimalThemeInformation> {
|
||||
id: theme.id,
|
||||
title: theme.title,
|
||||
shortDescription: LayerOverviewUtils.cleanTranslation(theme.shortDescription),
|
||||
|
@ -342,7 +342,7 @@ class LayerOverviewUtils extends Script {
|
|||
)
|
||||
}
|
||||
|
||||
writeTheme(theme: LayoutConfigJson) {
|
||||
writeTheme(theme: ThemeConfigJson) {
|
||||
if (!existsSync(LayerOverviewUtils.themePath)) {
|
||||
mkdirSync(LayerOverviewUtils.themePath)
|
||||
}
|
||||
|
@ -519,7 +519,7 @@ class LayerOverviewUtils extends Script {
|
|||
)
|
||||
|
||||
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) {
|
||||
|
@ -545,7 +545,7 @@ class LayerOverviewUtils extends Script {
|
|||
if: "theme=" + th.id,
|
||||
then: th.icon,
|
||||
}))
|
||||
const proto: LayoutConfigJson = JSON.parse(
|
||||
const proto: ThemeConfigJson = JSON.parse(
|
||||
readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", {
|
||||
encoding: "utf8",
|
||||
}),
|
||||
|
@ -689,7 +689,7 @@ class LayerOverviewUtils extends Script {
|
|||
* @param themeFile
|
||||
* @private
|
||||
*/
|
||||
private extractJavascriptCode(themeFile: LayoutConfigJson) {
|
||||
private extractJavascriptCode(themeFile: ThemeConfigJson) {
|
||||
const allCode = [
|
||||
"import {Feature} from 'geojson'",
|
||||
"import { ExtraFuncType } from \"../../../Logic/ExtraFunctions\";",
|
||||
|
@ -804,10 +804,10 @@ class LayerOverviewUtils extends Script {
|
|||
recompiledThemes: string[],
|
||||
forceReload: boolean,
|
||||
whitelist: Set<string>,
|
||||
): Map<string, LayoutConfigJson> {
|
||||
): Map<string, ThemeConfigJson> {
|
||||
console.log(" ---------- VALIDATING BUILTIN THEMES ---------")
|
||||
const themeFiles = ScriptUtils.getThemeFiles()
|
||||
const fixed = new Map<string, LayoutConfigJson>()
|
||||
const fixed = new Map<string, ThemeConfigJson>()
|
||||
|
||||
const publicLayers = LayerOverviewUtils.publicLayerIdsFrom(
|
||||
themeFiles.map((th) => th.parsed),
|
||||
|
|
|
@ -3,8 +3,8 @@ import Locale from "../src/UI/i18n/Locale"
|
|||
import Translations from "../src/UI/i18n/Translations"
|
||||
import { Translation } from "../src/UI/i18n/Translation"
|
||||
import all_known_layouts from "../src/assets/generated/known_themes.json"
|
||||
import { LayoutConfigJson } from "../src/Models/ThemeConfig/Json/LayoutConfigJson"
|
||||
import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig"
|
||||
import { ThemeConfigJson } from "../src/Models/ThemeConfig/Json/ThemeConfigJson"
|
||||
import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig"
|
||||
import xml2js from "xml2js"
|
||||
import ScriptUtils from "./ScriptUtils"
|
||||
import { Utils } from "../src/Utils"
|
||||
|
@ -100,7 +100,7 @@ class GenerateLayouts extends Script {
|
|||
return newname
|
||||
}
|
||||
|
||||
async createSocialImage(layout: LayoutConfig, template: "" | "Wide"): Promise<string> {
|
||||
async createSocialImage(layout: ThemeConfig, template: "" | "Wide"): Promise<string> {
|
||||
if (!layout.icon.endsWith(".svg")) {
|
||||
console.warn(
|
||||
"Not creating a social image for " +
|
||||
|
@ -160,7 +160,7 @@ class GenerateLayouts extends Script {
|
|||
}
|
||||
|
||||
async createManifest(
|
||||
layout: LayoutConfig,
|
||||
layout: ThemeConfig,
|
||||
alreadyWritten: string[]
|
||||
): Promise<{
|
||||
manifest: any
|
||||
|
@ -319,8 +319,8 @@ class GenerateLayouts extends Script {
|
|||
}
|
||||
|
||||
async generateCsp(
|
||||
layout: LayoutConfig,
|
||||
layoutJson: LayoutConfigJson,
|
||||
layout: ThemeConfig,
|
||||
layoutJson: ThemeConfigJson,
|
||||
options: {
|
||||
scriptSrcs: string[]
|
||||
}
|
||||
|
@ -441,8 +441,8 @@ class GenerateLayouts extends Script {
|
|||
}
|
||||
|
||||
async createLandingPage(
|
||||
layout: LayoutConfig,
|
||||
layoutJson: LayoutConfigJson,
|
||||
layout: ThemeConfig,
|
||||
layoutJson: ThemeConfigJson,
|
||||
whiteIcons,
|
||||
alreadyWritten
|
||||
) {
|
||||
|
@ -456,7 +456,7 @@ class GenerateLayouts extends Script {
|
|||
.replace(/"/g, '\\"')
|
||||
let ogImage = layout.socialImage
|
||||
let twitterImage = ogImage
|
||||
if (ogImage === LayoutConfig.defaultSocialImage && layout.official) {
|
||||
if (ogImage === ThemeConfig.defaultSocialImage && layout.official) {
|
||||
try {
|
||||
ogImage = (await this.createSocialImage(layout, "")) ?? 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 imports = [
|
||||
|
@ -628,18 +628,18 @@ class GenerateLayouts extends Script {
|
|||
"theme",
|
||||
]
|
||||
// @ts-ignore
|
||||
const all: LayoutConfigJson[] = all_known_layouts.themes
|
||||
const all: ThemeConfigJson[] = all_known_layouts.themes
|
||||
const args = process.argv
|
||||
const theme = args[2]
|
||||
if (theme !== undefined) {
|
||||
console.warn("Only generating layout " + theme)
|
||||
}
|
||||
for (const i in all) {
|
||||
const layoutConfigJson: LayoutConfigJson = all[i]
|
||||
const layoutConfigJson: ThemeConfigJson = all[i]
|
||||
if (theme !== undefined && layoutConfigJson.id !== theme) {
|
||||
continue
|
||||
}
|
||||
const layout = new LayoutConfig(layoutConfigJson, true)
|
||||
const layout = new ThemeConfig(layoutConfigJson, true)
|
||||
const layoutName = layout.id
|
||||
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {
|
||||
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(
|
||||
new LayoutConfig({
|
||||
new ThemeConfig({
|
||||
icon: "./assets/svg/mapcomplete_logo.svg",
|
||||
id: "index",
|
||||
layers: [],
|
||||
|
|
|
@ -2,7 +2,7 @@ import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts"
|
|||
import Locale from "../src/UI/i18n/Locale"
|
||||
import { Translation } from "../src/UI/i18n/Translation"
|
||||
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 { Utils } from "../src/Utils"
|
||||
|
||||
|
@ -33,7 +33,7 @@ function generateTagOverview(
|
|||
return overview
|
||||
}
|
||||
|
||||
function generateLayerUsage(layer: LayerConfig, layout: LayoutConfig): any[] {
|
||||
function generateLayerUsage(layer: LayerConfig, layout: ThemeConfig): any[] {
|
||||
if (layer.name === undefined) {
|
||||
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
|
||||
* @param layout
|
||||
*/
|
||||
function generateTagInfoEntry(layout: LayoutConfig): any {
|
||||
function generateTagInfoEntry(layout: ThemeConfig): any {
|
||||
const usedTags = []
|
||||
for (const layer of layout.layers) {
|
||||
if (layer.source === null) {
|
||||
|
|
|
@ -15,7 +15,7 @@ type ErrorMessage = {
|
|||
message: {
|
||||
stacktrace: string
|
||||
message: string
|
||||
layout: string
|
||||
theme: string
|
||||
version: string
|
||||
language: string
|
||||
username: string
|
||||
|
@ -40,7 +40,7 @@ class HandleErrors extends Script {
|
|||
) {
|
||||
console.log(
|
||||
parsed.message.username,
|
||||
parsed.message.layout,
|
||||
parsed.message.theme,
|
||||
parsed.message.message,
|
||||
parsed.date
|
||||
)
|
||||
|
@ -82,7 +82,7 @@ class HandleErrors extends Script {
|
|||
} = changesObj.CreateChangesetObjects(toUpload, objects, true)
|
||||
|
||||
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 (
|
||||
changeset ===
|
||||
`<osmChange version='0.6' generator='Mapcomplete ${Constants.vNumber}'></osmChange>`
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
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 { LayoutConfigJson } from "../Models/ThemeConfig/Json/LayoutConfigJson"
|
||||
import { ThemeConfigJson } from "../Models/ThemeConfig/Json/ThemeConfigJson"
|
||||
import { AllSharedLayers } from "./AllSharedLayers"
|
||||
import Constants from "../Models/Constants"
|
||||
|
||||
|
@ -9,8 +9,8 @@ import Constants from "../Models/Constants"
|
|||
* Somewhat of a dictionary, which lazily parses needed themes
|
||||
*/
|
||||
export class AllKnownLayoutsLazy {
|
||||
private readonly raw: Map<string, LayoutConfigJson> = new Map()
|
||||
private readonly dict: Map<string, LayoutConfig> = new Map()
|
||||
private readonly raw: Map<string, ThemeConfigJson> = new Map()
|
||||
private readonly dict: Map<string, ThemeConfig> = new Map()
|
||||
|
||||
constructor(includeFavouriteLayer = true) {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -40,13 +40,13 @@ export class AllKnownLayoutsLazy {
|
|||
return this.raw.size
|
||||
}
|
||||
|
||||
public get(key: string): LayoutConfig {
|
||||
public get(key: string): ThemeConfig {
|
||||
const cached = this.dict.get(key)
|
||||
if (cached !== undefined) {
|
||||
return cached
|
||||
}
|
||||
|
||||
const layout = new LayoutConfig(this.getConfig(key))
|
||||
const layout = new ThemeConfig(this.getConfig(key))
|
||||
this.dict.set(key, layout)
|
||||
return layout
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ImmutableStore, Store, UIEventSource } from "../UIEventSource"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
import { QueryParameters } from "../Web/QueryParameters"
|
||||
import Hash from "../Web/Hash"
|
||||
|
@ -25,7 +25,7 @@ export default class InitialMapPositioning {
|
|||
public location: UIEventSource<{ lon: number; lat: number }>
|
||||
public useTerrain: Store<boolean>
|
||||
|
||||
constructor(layoutToUse: LayoutConfig, geolocationState: GeoLocationState) {
|
||||
constructor(layoutToUse: ThemeConfig, geolocationState: GeoLocationState) {
|
||||
function localStorageSynced(
|
||||
key: string,
|
||||
deflt: number,
|
||||
|
|
|
@ -14,7 +14,7 @@ export default class NoElementsInViewDetector {
|
|||
constructor(themeViewState: ThemeViewState) {
|
||||
const state = themeViewState
|
||||
const minZoom = Math.min(
|
||||
...themeViewState.layout.layers
|
||||
...themeViewState.theme.layers
|
||||
.filter((l) => Constants.priviliged_layers.indexOf(<any>l.id) < 0)
|
||||
.map((l) => l.minzoom)
|
||||
)
|
||||
|
@ -43,7 +43,7 @@ export default class NoElementsInViewDetector {
|
|||
// Nope, no data loaded
|
||||
continue
|
||||
}
|
||||
const layer = themeViewState.layout.getLayer(layerName)
|
||||
const layer = themeViewState.theme.getLayer(layerName)
|
||||
if (mapProperties.zoom.data < layer.minzoom) {
|
||||
minzoomWithData = Math.min(layer.minzoom)
|
||||
continue
|
||||
|
@ -67,7 +67,7 @@ export default class NoElementsInViewDetector {
|
|||
continue
|
||||
}
|
||||
|
||||
const layer = themeViewState.layout.getLayer(layerName)
|
||||
const layer = themeViewState.theme.getLayer(layerName)
|
||||
if (mapProperties.zoom.data < layer.minzoom) {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export default class SelectedElementTagsUpdater {
|
|||
|
||||
public static applyUpdate(latestTags: OsmTags, id: string, state: SpecialVisualizationState) {
|
||||
try {
|
||||
const leftRightSensitive = state.layout.isLeftRightSensitive()
|
||||
const leftRightSensitive = state.theme.isLeftRightSensitive()
|
||||
|
||||
if (leftRightSensitive) {
|
||||
SimpleMetaTagger.removeBothTagging(latestTags)
|
||||
|
@ -111,7 +111,7 @@ export default class SelectedElementTagsUpdater {
|
|||
}
|
||||
private invalidateCache(s: Feature) {
|
||||
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))
|
||||
}
|
||||
private installCallback() {
|
||||
|
|
|
@ -12,11 +12,11 @@ export default class TitleHandler {
|
|||
const currentTitle: Store<string> = selectedElement.map(
|
||||
(selected) => {
|
||||
const lng = Locale.language.data
|
||||
const defaultTitle = state.layout?.title?.textFor(lng) ?? "MapComplete"
|
||||
const defaultTitle = state.theme?.title?.textFor(lng) ?? "MapComplete"
|
||||
if (selected === undefined) {
|
||||
return defaultTitle
|
||||
}
|
||||
const layer = state.layout.getMatchingLayer(selected.properties)
|
||||
const layer = state.theme.getMatchingLayer(selected.properties)
|
||||
if (layer === undefined) {
|
||||
return defaultTitle
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||
import { QueryParameters } from "./Web/QueryParameters"
|
||||
import { AllKnownLayouts } from "../Customizations/AllKnownLayouts"
|
||||
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 Hash from "./Web/Hash"
|
||||
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"
|
||||
|
||||
export default class DetermineLayout {
|
||||
export default class DetermineTheme {
|
||||
private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path))
|
||||
private static readonly loadCustomThemeParam = QueryParameters.GetQueryParameter(
|
||||
"userlayout",
|
||||
|
@ -31,7 +31,7 @@ export default class DetermineLayout {
|
|||
)
|
||||
|
||||
public static getCustomDefinition(): string {
|
||||
const layoutFromBase64 = decodeURIComponent(DetermineLayout.loadCustomThemeParam.data)
|
||||
const layoutFromBase64 = decodeURIComponent(DetermineTheme.loadCustomThemeParam.data)
|
||||
|
||||
if (layoutFromBase64.startsWith("http")) {
|
||||
return layoutFromBase64
|
||||
|
@ -53,8 +53,8 @@ export default class DetermineLayout {
|
|||
}
|
||||
|
||||
private static async expandRemoteLayers(
|
||||
layoutConfig: LayoutConfigJson
|
||||
): Promise<LayoutConfigJson> {
|
||||
layoutConfig: ThemeConfigJson
|
||||
): Promise<ThemeConfigJson> {
|
||||
if (!layoutConfig.layers) {
|
||||
// This is probably a layer in 'layer-only-mode'
|
||||
return layoutConfig
|
||||
|
@ -79,16 +79,16 @@ export default class DetermineLayout {
|
|||
/**
|
||||
* Gets the correct layout for this website
|
||||
*/
|
||||
public static async GetLayout(): Promise<LayoutConfig | undefined> {
|
||||
const layoutFromBase64 = decodeURIComponent(DetermineLayout.loadCustomThemeParam.data)
|
||||
public static async getTheme(): Promise<ThemeConfig | undefined> {
|
||||
const layoutFromBase64 = decodeURIComponent(DetermineTheme.loadCustomThemeParam.data)
|
||||
|
||||
if (layoutFromBase64.startsWith("http")) {
|
||||
return await DetermineLayout.LoadRemoteTheme(layoutFromBase64)
|
||||
return await DetermineTheme.LoadRemoteTheme(layoutFromBase64)
|
||||
}
|
||||
|
||||
if (layoutFromBase64 !== "false") {
|
||||
// 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
|
||||
|
@ -127,7 +127,7 @@ export default class DetermineLayout {
|
|||
|
||||
public static async LoadLayoutFromHash(
|
||||
userLayoutParam: UIEventSource<string>
|
||||
): Promise<LayoutConfig | null> {
|
||||
): Promise<ThemeConfig | null> {
|
||||
let hash = location.hash.substr(1)
|
||||
let json: any
|
||||
|
||||
|
@ -157,7 +157,7 @@ export default class DetermineLayout {
|
|||
|
||||
json = await this.expandRemoteLayers(json)
|
||||
|
||||
const layoutToUse = DetermineLayout.prepCustomTheme(json)
|
||||
const layoutToUse = DetermineTheme.prepCustomTheme(json)
|
||||
userLayoutParam.setData(layoutToUse.id)
|
||||
return layoutToUse
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ export default class DetermineLayout {
|
|||
const dict = new Map<string, QuestionableTagRenderingConfigJson>()
|
||||
|
||||
for (const tagRendering of questions.tagRenderings) {
|
||||
dict.set(tagRendering.id, tagRendering)
|
||||
dict.set(tagRendering.id, <QuestionableTagRenderingConfigJson> tagRendering)
|
||||
}
|
||||
|
||||
return dict
|
||||
|
@ -176,7 +176,7 @@ export default class DetermineLayout {
|
|||
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) {
|
||||
// We got fed a layer instead of a theme
|
||||
const layerConfig = <LayerConfigJson>json
|
||||
|
@ -224,15 +224,15 @@ export default class DetermineLayout {
|
|||
knownLayersDict.set(layer.id, <LayerConfigJson>layer)
|
||||
}
|
||||
const convertState: DesugaringContext = {
|
||||
tagRenderings: DetermineLayout.getSharedTagRenderings(),
|
||||
tagRenderingOrder: DetermineLayout.getSharedTagRenderingOrder(),
|
||||
tagRenderings: DetermineTheme.getSharedTagRenderings(),
|
||||
tagRenderingOrder: DetermineTheme.getSharedTagRenderingOrder(),
|
||||
sharedLayers: knownLayersDict,
|
||||
publicLayers: new Set<string>(),
|
||||
}
|
||||
json = new FixLegacyTheme().convertStrict(json)
|
||||
const raw = json
|
||||
|
||||
json = new FixImages(DetermineLayout._knownImages).convertStrict(json)
|
||||
json = new FixImages(DetermineTheme._knownImages).convertStrict(json)
|
||||
json.enableNoteImports = json.enableNoteImports ?? false
|
||||
json = new PrepareTheme(convertState).convertStrict(json)
|
||||
console.log("The layoutconfig is ", json)
|
||||
|
@ -249,20 +249,20 @@ export default class DetermineLayout {
|
|||
false
|
||||
).convertStrict(json)
|
||||
}
|
||||
return new LayoutConfig(json, false, {
|
||||
return new ThemeConfig(json, false, {
|
||||
definitionRaw: JSON.stringify(raw, null, " "),
|
||||
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)
|
||||
|
||||
new FixedUiElement(`Downloading the theme from the <a href="${link}">link</a>...`).AttachTo(
|
||||
"maindiv"
|
||||
)
|
||||
|
||||
let parsed = <LayoutConfigJson>await Utils.downloadJson(link)
|
||||
let parsed = <ThemeConfigJson>await Utils.downloadJson(link)
|
||||
let forcedId = parsed.id
|
||||
const url = new URL(link)
|
||||
if (!(url.hostname === "localhost" || url.hostname === "127.0.0.1")) {
|
||||
|
@ -270,6 +270,6 @@ export default class DetermineLayout {
|
|||
}
|
||||
console.log("Loaded remote link:", link)
|
||||
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) =>
|
||||
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 { Feature, Point } from "geojson"
|
||||
import { TagUtils } from "../../Tags/TagUtils"
|
||||
|
@ -22,7 +22,7 @@ export class LastClickFeatureSource implements FeatureSource {
|
|||
private _usermode: UIEventSource<string>
|
||||
private _enabledAddMorePoints: UIEventSource<boolean>
|
||||
constructor(
|
||||
layout: LayoutConfig,
|
||||
layout: ThemeConfig,
|
||||
clickSource: Store<{ lon: number; lat: number; mode: "left" | "right" | "middle" }>,
|
||||
usermode?: UIEventSource<string>,
|
||||
enabledAddMorePoints?: UIEventSource<boolean>
|
||||
|
|
|
@ -18,7 +18,7 @@ import FeatureSourceMerger from "./FeatureSourceMerger"
|
|||
*
|
||||
* 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
|
||||
*/
|
||||
|
@ -51,7 +51,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
const src = new LocalStorageFeatureSource(
|
||||
backend,
|
||||
layer,
|
||||
LayoutSource.fromCacheZoomLevel,
|
||||
ThemeSource.fromCacheZoomLevel,
|
||||
mapProperties,
|
||||
{
|
||||
isActive: isDisplayed(layer.id),
|
||||
|
@ -63,13 +63,13 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
}
|
||||
const mvtSources: UpdatableFeatureSource[] = osmLayers
|
||||
.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 nonMvtLayers = osmLayers.filter((l) => !mvtAvailableLayers.has(l.id))
|
||||
|
||||
const isLoading = new UIEventSource(false)
|
||||
|
||||
const osmApiSource = LayoutSource.setupOsmApiSource(
|
||||
const osmApiSource = ThemeSource.setupOsmApiSource(
|
||||
osmLayers,
|
||||
bounds,
|
||||
zoom,
|
||||
|
@ -86,7 +86,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
nonMvtLayers.map((l) => l.id),
|
||||
" 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)
|
||||
supportsForceDownload.push(overpassSource)
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
osmApiSource?.isRunning?.addCallbackAndRun(() => setIsLoading())
|
||||
|
||||
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)
|
||||
|
@ -198,7 +198,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
zoom,
|
||||
bounds,
|
||||
layers: osmLayers,
|
||||
widenFactor: featureSwitches.layoutToUse.widenFactor,
|
||||
widenFactor: 1.5,
|
||||
overpassUrl: featureSwitches.overpassUrl,
|
||||
overpassTimeout: featureSwitches.overpassTimeout,
|
||||
overpassMaxZoom: featureSwitches.overpassMaxZoom,
|
|
@ -2,7 +2,7 @@ import { ImageUploader, UploadResult } from "./ImageUploader"
|
|||
import LinkImageAction from "../Osm/Actions/LinkImageAction"
|
||||
import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore"
|
||||
import { OsmId, OsmTags } from "../../Models/OsmFeature"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import { OsmConnection } from "../Osm/OsmConnection"
|
||||
import { Changes } from "../Osm/Changes"
|
||||
|
@ -17,7 +17,7 @@ import { GeoOperations } from "../GeoOperations"
|
|||
export class ImageUploadManager {
|
||||
private readonly _uploader: ImageUploader
|
||||
private readonly _featureProperties: FeaturePropertiesStore
|
||||
private readonly _layout: LayoutConfig
|
||||
private readonly _theme: ThemeConfig
|
||||
private readonly _indexedFeatures: IndexedFeatureSource
|
||||
private readonly _gps: Store<GeolocationCoordinates | undefined>
|
||||
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>
|
||||
|
||||
constructor(
|
||||
layout: LayoutConfig,
|
||||
layout: ThemeConfig,
|
||||
uploader: ImageUploader,
|
||||
featureProperties: FeaturePropertiesStore,
|
||||
osmConnection: OsmConnection,
|
||||
|
@ -42,7 +42,7 @@ export class ImageUploadManager {
|
|||
) {
|
||||
this._uploader = uploader
|
||||
this._featureProperties = featureProperties
|
||||
this._layout = layout
|
||||
this._theme = layout
|
||||
this._osmConnection = osmConnection
|
||||
this._changes = changes
|
||||
this._indexedFeatures = allFeatures
|
||||
|
@ -131,7 +131,7 @@ export class ImageUploadManager {
|
|||
const properties = this._featureProperties.getStore(featureId)
|
||||
|
||||
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",
|
||||
})
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { ExtraFuncParams, ExtraFunctions, ExtraFuncType } from "./ExtraFunctions
|
|||
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||
import { Feature } from "geojson"
|
||||
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 { IndexedFeatureSource } from "./FeatureSource/FeatureSource"
|
||||
import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
|
||||
|
@ -27,7 +27,7 @@ export default class MetaTagging {
|
|||
>()
|
||||
private state: {
|
||||
readonly selectedElement: Store<Feature>
|
||||
readonly layout: LayoutConfig
|
||||
readonly theme: ThemeConfig
|
||||
readonly osmObjectDownloader: OsmObjectDownloader
|
||||
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
||||
readonly indexedFeatures: IndexedFeatureSource
|
||||
|
@ -40,7 +40,7 @@ export default class MetaTagging {
|
|||
|
||||
constructor(state: {
|
||||
readonly selectedElement: Store<Feature>
|
||||
readonly layout: LayoutConfig
|
||||
readonly theme: ThemeConfig
|
||||
readonly osmObjectDownloader: OsmObjectDownloader
|
||||
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
||||
readonly indexedFeatures: IndexedFeatureSource
|
||||
|
@ -48,7 +48,7 @@ export default class MetaTagging {
|
|||
}) {
|
||||
this.state = 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) {
|
||||
continue
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ export default class MetaTagging {
|
|||
features,
|
||||
params,
|
||||
layer,
|
||||
state.layout,
|
||||
state.theme,
|
||||
state.osmObjectDownloader,
|
||||
state.featureProperties
|
||||
)
|
||||
|
@ -115,7 +115,7 @@ export default class MetaTagging {
|
|||
return
|
||||
}
|
||||
const state = this.state
|
||||
const layer = state.layout.getMatchingLayer(feature.properties)
|
||||
const layer = state.theme.getMatchingLayer(feature.properties)
|
||||
if (!layer) {
|
||||
return
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ export default class MetaTagging {
|
|||
[feature],
|
||||
this.params,
|
||||
layer,
|
||||
state.layout,
|
||||
state.theme,
|
||||
state.osmObjectDownloader,
|
||||
state.featureProperties,
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ export default class MetaTagging {
|
|||
features: Feature[],
|
||||
params: ExtraFuncParams,
|
||||
layer: LayerConfig,
|
||||
layout: LayoutConfig,
|
||||
theme: ThemeConfig,
|
||||
osmObjectDownloader: OsmObjectDownloader,
|
||||
featurePropertiesStores?: FeaturePropertiesStore,
|
||||
options?: {
|
||||
|
@ -190,7 +190,7 @@ export default class MetaTagging {
|
|||
// The calculated functions - per layer - which add the new keys
|
||||
// Calculated functions are defined by the layer
|
||||
const layerFuncs = this.createRetaggingFunc(layer, ExtraFunctions.constructHelpers(params))
|
||||
const state: MetataggingState = { layout, osmObjectDownloader }
|
||||
const state: MetataggingState = { theme: theme, osmObjectDownloader }
|
||||
|
||||
let atLeastOneFeatureChanged = false
|
||||
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(
|
||||
"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 { TagUtils } from "../../Tags/TagUtils"
|
||||
import { FeatureSource, IndexedFeatureSource } from "../../FeatureSource/FeatureSource"
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||
import { Position } from "geojson"
|
||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
||||
|
@ -32,7 +32,7 @@ export default class CreateMultiPolygonWithPointReuseAction
|
|||
outerRingCoordinates: Position[],
|
||||
innerRingsCoordinates: Position[][],
|
||||
state: {
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
|
@ -43,7 +43,7 @@ export default class CreateMultiPolygonWithPointReuseAction
|
|||
super(null, true)
|
||||
this._tags = [...tags, new Tag("type", "multipolygon")]
|
||||
this.changeType = changeType
|
||||
this.theme = state?.layout?.id ?? ""
|
||||
this.theme = state?.theme?.id ?? ""
|
||||
this.createOuterWay = new CreateWayWithPointReuseAction(
|
||||
[],
|
||||
<[number, number][]>outerRingCoordinates,
|
||||
|
@ -55,7 +55,7 @@ export default class CreateMultiPolygonWithPointReuseAction
|
|||
new CreateNewWayAction(
|
||||
[],
|
||||
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 CreateNewNodeAction from "./CreateNewNodeAction"
|
||||
import CreateNewWayAction from "./CreateNewWayAction"
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
import { Position } from "geojson"
|
||||
|
||||
|
@ -69,7 +69,7 @@ export default class CreateWayWithPointReuseAction
|
|||
*/
|
||||
private readonly _coordinateInfo: CoordinateInfo[]
|
||||
private readonly _state: {
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
|
@ -80,7 +80,7 @@ export default class CreateWayWithPointReuseAction
|
|||
tags: Tag[],
|
||||
coordinates: Position[],
|
||||
state: {
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
|
@ -203,7 +203,7 @@ export default class CreateWayWithPointReuseAction
|
|||
}
|
||||
|
||||
public async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
|
||||
const theme = this._state?.layout?.id
|
||||
const theme = this._state?.theme?.id
|
||||
const allChanges: ChangeDescription[] = []
|
||||
const nodeIdsToUse: { lat: number; lon: number; nodeId?: number }[] = []
|
||||
for (let i = 0; i < this._coordinateInfo.length; i++) {
|
||||
|
|
|
@ -217,7 +217,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
const url = `${
|
||||
this.state.osmConnection?._oauth_config?.url ?? "https://api.openstreetmap.org"
|
||||
}/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)
|
||||
}
|
||||
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 LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
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 }
|
||||
|
||||
|
@ -13,9 +13,9 @@ export type FilterSearchResult = { option: FilterConfigOption, filter: FilterCon
|
|||
* Searches matching filters
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ export default class FilterSearch {
|
|||
return query
|
||||
}).filter(q => q.length > 0)
|
||||
const possibleFilters: FilterSearchResult[] = []
|
||||
for (const layer of this._state.layout.layers) {
|
||||
for (const layer of this._state.theme.layers) {
|
||||
if (!Array.isArray(layer.filters)) {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import SearchUtils from "./SearchUtils"
|
||||
import ThemeSearch from "./ThemeSearch"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import { Utils } from "../../Utils"
|
||||
|
||||
export default class LayerSearch {
|
||||
|
||||
private readonly _layout: LayoutConfig
|
||||
private readonly _theme: ThemeConfig
|
||||
private readonly _layerWhitelist: Set<string>
|
||||
|
||||
constructor(layout: LayoutConfig) {
|
||||
this._layout = layout
|
||||
this._layerWhitelist = new Set(layout.layers
|
||||
constructor(theme: ThemeConfig) {
|
||||
this._theme = theme
|
||||
this._layerWhitelist = new Set(theme.layers
|
||||
.filter(l => l.isNormal())
|
||||
.map(l => l.id))
|
||||
}
|
||||
|
@ -29,8 +29,7 @@ export default class LayerSearch {
|
|||
continue
|
||||
}
|
||||
const keywords = ThemeSearch.officialThemes.layers[id]
|
||||
const distance = Math.min(...queryParts.map(q => SearchUtils.scoreKeywords(q, keywords)))
|
||||
result[id] = distance
|
||||
result[id] = Math.min(...queryParts.map(q => SearchUtils.scoreKeywords(q, keywords)))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -44,7 +43,7 @@ export default class LayerSearch {
|
|||
const asList: ({ layer: LayerConfig, score: number })[] = []
|
||||
for (const layer in scores) {
|
||||
asList.push({
|
||||
layer: this._layout.getLayer(layer),
|
||||
layer: this._theme.getLayer(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 UserRelatedState from "../State/UserRelatedState"
|
||||
import { Utils } from "../../Utils"
|
||||
|
@ -10,7 +10,7 @@ import { OsmConnection } from "../Osm/OsmConnection"
|
|||
|
||||
|
||||
type ThemeSearchScore = {
|
||||
theme: MinimalLayoutInformation,
|
||||
theme: MinimalThemeInformation,
|
||||
lowest: number,
|
||||
perLayer?: Record<string, number>,
|
||||
other: number,
|
||||
|
@ -20,10 +20,10 @@ type ThemeSearchScore = {
|
|||
export default class ThemeSearch {
|
||||
|
||||
public static readonly officialThemes: {
|
||||
themes: MinimalLayoutInformation[],
|
||||
themes: MinimalThemeInformation[],
|
||||
layers: Record<string, Record<string, string[]>>
|
||||
} = <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 {
|
||||
for (const th of ThemeSearch.officialThemes.themes ?? []) {
|
||||
ThemeSearch.officialThemesById.set(th.id, th)
|
||||
|
@ -33,17 +33,17 @@ export default class ThemeSearch {
|
|||
|
||||
private readonly _knownHiddenThemes: Store<Set<string>>
|
||||
private readonly _layersToIgnore: string[]
|
||||
private readonly _otherThemes: MinimalLayoutInformation[]
|
||||
private readonly _otherThemes: MinimalThemeInformation[]
|
||||
|
||||
constructor(state: {osmConnection: OsmConnection, layout: LayoutConfig}) {
|
||||
this._layersToIgnore = state.layout.layers.filter(l => l.isNormal()).map(l => l.id)
|
||||
constructor(state: {osmConnection: OsmConnection, theme: ThemeConfig}) {
|
||||
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._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) {
|
||||
return []
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ export default class ThemeSearch {
|
|||
* @param ignoreLayers
|
||||
* @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) {
|
||||
return undefined
|
||||
}
|
||||
|
@ -147,13 +147,13 @@ export default class ThemeSearch {
|
|||
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))
|
||||
scored.sort((a, b) => a.lowest - b.lowest)
|
||||
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)
|
||||
.map(th => th.theme)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { TagUtils } from "./Tags/TagUtils"
|
|||
import { Feature, LineString } from "geojson"
|
||||
import { OsmTags } from "../Models/OsmFeature"
|
||||
import { UIEventSource } from "./UIEventSource"
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||
import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
|
||||
import countryToCurrency from "country-to-currency"
|
||||
|
||||
|
@ -16,7 +16,7 @@ import countryToCurrency from "country-to-currency"
|
|||
* All elements that are needed to perform metatagging
|
||||
*/
|
||||
export interface MetataggingState {
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
osmObjectDownloader: OsmObjectDownloader
|
||||
}
|
||||
|
||||
|
@ -399,7 +399,7 @@ export default class SimpleMetaTaggers {
|
|||
},
|
||||
(feature, _, __, state) => {
|
||||
const units = Utils.NoNull(
|
||||
[].concat(...(state?.layout?.layers?.map((layer) => layer.units) ?? []))
|
||||
[].concat(...(state?.theme?.layers?.map((layer) => layer.units) ?? []))
|
||||
)
|
||||
if (units.length == 0) {
|
||||
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 { QueryParameters } from "../Web/QueryParameters"
|
||||
import Constants from "../../Models/Constants"
|
||||
|
@ -45,10 +45,6 @@ export class 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 featureSwitchSearch: UIEventSource<boolean>
|
||||
|
@ -74,9 +70,8 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
public readonly featureSwitchMorePrivacy: UIEventSource<boolean>
|
||||
public readonly featureSwitchLayerDefault: UIEventSource<boolean>
|
||||
|
||||
public constructor(layoutToUse?: LayoutConfig) {
|
||||
public constructor(theme?: ThemeConfig) {
|
||||
super()
|
||||
this.layoutToUse = layoutToUse
|
||||
|
||||
const legacyRewrite: Record<string, string | string[]> = {
|
||||
"fs-userbadge": "fs-enable-login",
|
||||
|
@ -102,7 +97,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
|
||||
this.featureSwitchEnableLogin = FeatureSwitchUtils.initSwitch(
|
||||
"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."
|
||||
)
|
||||
{
|
||||
|
@ -117,18 +112,18 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
|
||||
this.featureSwitchSearch = FeatureSwitchUtils.initSwitch(
|
||||
"fs-search",
|
||||
layoutToUse?.enableSearch ?? true,
|
||||
theme?.enableSearch ?? true,
|
||||
"Disables/Enables the search bar"
|
||||
)
|
||||
this.featureSwitchBackgroundSelection = FeatureSwitchUtils.initSwitch(
|
||||
"fs-background",
|
||||
layoutToUse?.enableBackgroundLayerSelection ?? true,
|
||||
theme?.enableBackgroundLayerSelection ?? true,
|
||||
"Disables/Enables the background layer control where a user can enable e.g. aerial imagery"
|
||||
)
|
||||
|
||||
this.featureSwitchFilter = FeatureSwitchUtils.initSwitch(
|
||||
"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"
|
||||
)
|
||||
|
||||
|
@ -149,17 +144,17 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
)
|
||||
this.featureSwitchBackToThemeOverview = FeatureSwitchUtils.initSwitch(
|
||||
"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"
|
||||
)
|
||||
this.featureSwitchShareScreen = FeatureSwitchUtils.initSwitch(
|
||||
"fs-share-screen",
|
||||
layoutToUse?.enableShareScreen ?? true,
|
||||
theme?.enableShareScreen ?? true,
|
||||
"Disables/Enables the 'Share-screen'-tab in the welcome message"
|
||||
)
|
||||
this.featureSwitchGeolocation = FeatureSwitchUtils.initSwitch(
|
||||
"fs-geolocation",
|
||||
layoutToUse?.enableGeolocation ?? true,
|
||||
theme?.enableGeolocation ?? true,
|
||||
"Disables/Enables the geolocation button"
|
||||
)
|
||||
|
||||
|
@ -170,19 +165,19 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
)
|
||||
this.featureSwitchShowAllQuestions = FeatureSwitchUtils.initSwitch(
|
||||
"fs-all-questions",
|
||||
layoutToUse?.enableShowAllQuestions ?? false,
|
||||
theme?.enableShowAllQuestions ?? false,
|
||||
"Always show all questions"
|
||||
)
|
||||
|
||||
this.featureSwitchEnableExport = FeatureSwitchUtils.initSwitch(
|
||||
"fs-export",
|
||||
layoutToUse?.enableExportButton ?? true,
|
||||
theme?.enableExportButton ?? true,
|
||||
"Enable the export as GeoJSON and CSV button"
|
||||
)
|
||||
|
||||
this.featureSwitchCache = FeatureSwitchUtils.initSwitch(
|
||||
"fs-cache",
|
||||
layoutToUse?.enableCache ?? true,
|
||||
theme?.enableCache ?? true,
|
||||
"Enable/disable caching from localStorage"
|
||||
)
|
||||
|
||||
|
@ -209,13 +204,13 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
|
||||
this.featureSwitchMorePrivacy = QueryParameters.GetBooleanQueryParameter(
|
||||
"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."
|
||||
)
|
||||
|
||||
this.overpassUrl = QueryParameters.GetQueryParameter(
|
||||
"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"
|
||||
).sync(
|
||||
(param) => param?.split(","),
|
||||
|
@ -226,7 +221,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
this.overpassTimeout = UIEventSource.asInt(
|
||||
QueryParameters.GetQueryParameter(
|
||||
"overpassTimeout",
|
||||
"" + layoutToUse?.overpassTimeout,
|
||||
"" + theme?.overpassTimeout,
|
||||
"Set a different timeout (in seconds) for queries in overpass"
|
||||
)
|
||||
)
|
||||
|
@ -234,7 +229,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
this.overpassMaxZoom = UIEventSource.asFloat(
|
||||
QueryParameters.GetQueryParameter(
|
||||
"overpassMaxZoom",
|
||||
"" + layoutToUse?.overpassMaxZoom,
|
||||
"" + theme?.overpassMaxZoom,
|
||||
" point to switch between OSM-api and overpass"
|
||||
)
|
||||
)
|
||||
|
@ -242,14 +237,14 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
this.osmApiTileSize = UIEventSource.asInt(
|
||||
QueryParameters.GetQueryParameter(
|
||||
"osmApiTileSize",
|
||||
"" + layoutToUse?.osmApiTileSize,
|
||||
"" + theme?.osmApiTileSize,
|
||||
"Tilesize when the OSM-API is used to fetch data within a BBOX"
|
||||
)
|
||||
)
|
||||
|
||||
this.backgroundLayerId = QueryParameters.GetQueryParameter(
|
||||
"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.",
|
||||
"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 PhotonSearch from "../Search/PhotonSearch"
|
||||
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 GeocodingFeatureSource from "../Search/GeocodingFeatureSource"
|
||||
import LayerSearch from "../Search/LayerSearch"
|
||||
|
@ -23,7 +23,7 @@ export default class SearchState {
|
|||
public readonly searchIsFocused = new UIEventSource(false)
|
||||
public readonly suggestions: Store<SearchResult[]>
|
||||
public readonly filterSuggestions: Store<FilterSearchResult[]>
|
||||
public readonly themeSuggestions: Store<MinimalLayoutInformation[]>
|
||||
public readonly themeSuggestions: Store<MinimalThemeInformation[]>
|
||||
public readonly layerSuggestions: Store<LayerConfig[]>
|
||||
public readonly locationSearchers: ReadonlyArray<GeocodingProvider>
|
||||
|
||||
|
@ -64,7 +64,7 @@ export default class SearchState {
|
|||
const themeSearch = new ThemeSearch(state)
|
||||
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))
|
||||
|
||||
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 { MangroveIdentity } from "../Web/MangroveReviews"
|
||||
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
||||
|
@ -183,7 +183,7 @@ export default class UserRelatedState {
|
|||
|
||||
constructor(
|
||||
osmConnection: OsmConnection,
|
||||
layout?: LayoutConfig,
|
||||
layout?: ThemeConfig,
|
||||
featureSwitches?: FeatureSwitchState,
|
||||
mapProperties?: MapProperties,
|
||||
) {
|
||||
|
@ -277,14 +277,14 @@ export default class UserRelatedState {
|
|||
*
|
||||
* @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)
|
||||
this.osmConnection.isLoggedIn.when(
|
||||
() => 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 str = pref.data
|
||||
|
||||
|
@ -307,7 +307,7 @@ export default class UserRelatedState {
|
|||
}
|
||||
}
|
||||
|
||||
public markLayoutAsVisited(layout: LayoutConfig) {
|
||||
public markLayoutAsVisited(layout: ThemeConfig) {
|
||||
if (!layout) {
|
||||
console.error("Trying to mark a layout as visited, but ", layout, " got passed")
|
||||
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
|
||||
* */
|
||||
private initAmendedPrefs(
|
||||
layout?: LayoutConfig,
|
||||
layout?: ThemeConfig,
|
||||
featureSwitches?: FeatureSwitchState,
|
||||
): UIEventSource<Record<string, string>> {
|
||||
const amendedPrefs = new UIEventSource<Record<string, string>>({
|
||||
|
|
|
@ -30,13 +30,16 @@ export class LocalStorageSource {
|
|||
return cached
|
||||
}
|
||||
let saved = defaultValue
|
||||
try {
|
||||
saved = localStorage.getItem(key)
|
||||
if (saved === "undefined") {
|
||||
saved = undefined
|
||||
if (!Utils.runningFromConsole) {
|
||||
|
||||
try {
|
||||
saved = localStorage.getItem(key)
|
||||
if (saved === "undefined") {
|
||||
saved = undefined
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Could not get value", key, "from local storage")
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Could not get value", key, "from local storage")
|
||||
}
|
||||
const source = new UIEventSource<string>(saved ?? defaultValue, "localstorage:" + key)
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ export default class Constants {
|
|||
// The user journey states thresholds when a new feature gets unlocked
|
||||
public static userJourney = {
|
||||
moreScreenUnlock: 1,
|
||||
personalLayoutUnlock: 5,
|
||||
personalThemeUnlock: 5,
|
||||
historyLinkVisible: 10,
|
||||
deletePointsOfOthersUnlock: 20,
|
||||
tagsVisibleAt: 25,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Conversion, DesugaringStep } from "./Conversion"
|
||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
||||
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||
import { Utils } from "../../../Utils"
|
||||
import metapaths from "../../../assets/schemas/layoutconfigmeta.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"
|
||||
|
||||
export class ExtractImages extends Conversion<
|
||||
LayoutConfigJson,
|
||||
ThemeConfigJson,
|
||||
{ path: string; context: string }[]
|
||||
> {
|
||||
private static readonly layoutMetaPaths = metapaths.filter((mp) => {
|
||||
|
@ -109,7 +109,7 @@ export class ExtractImages extends Conversion<
|
|||
*
|
||||
*/
|
||||
convert(
|
||||
json: LayoutConfigJson,
|
||||
json: ThemeConfigJson,
|
||||
context: ConversionContext
|
||||
): { 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>
|
||||
|
||||
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].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
|
||||
try {
|
||||
url = new URL(json.id)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
||||
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||
import { Utils } from "../../../Utils"
|
||||
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
|
||||
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() {
|
||||
super("Small fixes in the theme config", ["roamingRenderings"], "UpdateLegacyTheme")
|
||||
}
|
||||
|
||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
||||
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||
const oldThemeConfig = { ...json }
|
||||
|
||||
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() {
|
||||
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)",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||
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
|
||||
|
||||
constructor(state: DesugaringContext) {
|
||||
|
@ -177,7 +177,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
|||
this._state = state
|
||||
}
|
||||
|
||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
||||
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||
const state = this._state
|
||||
json.layers = Utils.NoNull([...(json.layers ?? [])])
|
||||
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() {
|
||||
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",
|
||||
|
@ -218,8 +218,8 @@ class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson>
|
|||
)
|
||||
}
|
||||
|
||||
convert(json: LayoutConfigJson): LayoutConfigJson {
|
||||
const conversion = new AddContextToTranslations<LayoutConfigJson>("themes:")
|
||||
convert(json: ThemeConfigJson): ThemeConfigJson {
|
||||
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
|
||||
return conversion.convert(
|
||||
json,
|
||||
|
@ -228,7 +228,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson>
|
|||
}
|
||||
}
|
||||
|
||||
class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
||||
class ApplyOverrideAll extends DesugaringStep<ThemeConfigJson> {
|
||||
constructor() {
|
||||
super(
|
||||
"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
|
||||
if (overrideAll === undefined) {
|
||||
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
|
||||
|
||||
constructor(state: DesugaringContext) {
|
||||
|
@ -390,7 +390,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
return dependenciesToAdd
|
||||
}
|
||||
|
||||
convert(theme: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
||||
convert(theme: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||
const state = this._state
|
||||
const allKnownLayers: Map<string, LayerConfigJson> = state.sharedLayers
|
||||
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
|
||||
|
||||
constructor(state: DesugaringContext) {
|
||||
|
@ -436,7 +436,7 @@ class PreparePersonalTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
this._state = state
|
||||
}
|
||||
|
||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
||||
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||
if (json.id !== "personal") {
|
||||
return json
|
||||
}
|
||||
|
@ -452,7 +452,7 @@ class PreparePersonalTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
}
|
||||
}
|
||||
|
||||
class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson> {
|
||||
class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<ThemeConfigJson> {
|
||||
constructor() {
|
||||
super(
|
||||
"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) {
|
||||
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
|
||||
|
||||
constructor(state: DesugaringContext) {
|
||||
|
@ -511,7 +511,7 @@ class PostvalidateTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
this._state = state
|
||||
}
|
||||
|
||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
||||
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||
for (const l of json.layers) {
|
||||
const layer = <LayerConfigJson>l
|
||||
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
|
||||
|
||||
constructor(
|
||||
|
@ -616,7 +616,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
|||
this.state = state
|
||||
}
|
||||
|
||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
||||
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||
const result = super.convert(json, context)
|
||||
if ((this.state.publicLayers?.size ?? 0) === 0) {
|
||||
// THis is a bootstrapping run, no need to already set this flag
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { DesugaringStep } from "./Conversion"
|
||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
||||
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||
import { AvailableRasterLayers } from "../../RasterLayers"
|
||||
import { ExtractImages } from "./FixImages"
|
||||
import { ConversionContext } from "./ConversionContext"
|
||||
import LayoutConfig from "../LayoutConfig"
|
||||
import ThemeConfig from "../ThemeConfig"
|
||||
import { Utils } from "../../../Utils"
|
||||
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
|
||||
* @private
|
||||
|
@ -33,8 +33,8 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
}
|
||||
}
|
||||
|
||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
||||
const theme = new LayoutConfig(json, this._isBuiltin)
|
||||
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
|
||||
const theme = new ThemeConfig(json, this._isBuiltin)
|
||||
{
|
||||
// Legacy format checks
|
||||
if (this._isBuiltin) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Bypass, Each, Fuse, On } from "./Conversion"
|
||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
||||
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||
import Constants from "../../Constants"
|
||||
import { DoesImageExist, ValidateLayerConfig } from "./Validation"
|
||||
import { ValidateTheme } from "./ValidateTheme"
|
||||
|
||||
export class ValidateThemeAndLayers extends Fuse<LayoutConfigJson> {
|
||||
export class ValidateThemeAndLayers extends Fuse<ThemeConfigJson> {
|
||||
constructor(
|
||||
doesImageExist: DoesImageExist,
|
||||
path: string,
|
||||
|
|
|
@ -4,8 +4,8 @@ import LayerConfig from "../LayerConfig"
|
|||
import { Utils } from "../../../Utils"
|
||||
import Constants from "../../Constants"
|
||||
import { Translation } from "../../../UI/i18n/Translation"
|
||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
||||
import LayoutConfig from "../LayoutConfig"
|
||||
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||
import ThemeConfig from "../ThemeConfig"
|
||||
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
||||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||
import { And } from "../../../Logic/Tags/And"
|
||||
|
@ -23,7 +23,7 @@ import { PrevalidateLayer } from "./PrevalidateLayer"
|
|||
import { AvailableRasterLayers } from "../../RasterLayers"
|
||||
import { eliCategory } from "../../RasterLayerProperties"
|
||||
|
||||
export class ValidateLanguageCompleteness extends DesugaringStep<LayoutConfig> {
|
||||
export class ValidateLanguageCompleteness extends DesugaringStep<ThemeConfig> {
|
||||
private readonly _languages: string[]
|
||||
|
||||
constructor(...languages: string[]) {
|
||||
|
@ -35,7 +35,7 @@ export class ValidateLanguageCompleteness extends DesugaringStep<LayoutConfig> {
|
|||
this._languages = languages ?? ["en"]
|
||||
}
|
||||
|
||||
convert(obj: LayoutConfig, context: ConversionContext): LayoutConfig {
|
||||
convert(obj: ThemeConfig, context: ConversionContext): ThemeConfig {
|
||||
const origLayers = obj.layers
|
||||
obj.layers = [...obj.layers].filter((l) => l["id"] !== "favourite")
|
||||
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() {
|
||||
super(
|
||||
"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
|
||||
if (overrideAll === undefined) {
|
||||
return json
|
||||
|
@ -170,12 +170,12 @@ class OverrideShadowingCheck extends DesugaringStep<LayoutConfigJson> {
|
|||
}
|
||||
}
|
||||
|
||||
class MiscThemeChecks extends DesugaringStep<LayoutConfigJson> {
|
||||
class MiscThemeChecks extends DesugaringStep<ThemeConfigJson> {
|
||||
constructor() {
|
||||
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)) {
|
||||
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() {
|
||||
super(
|
||||
"Various consistency checks on the raw JSON",
|
||||
|
@ -905,7 +905,7 @@ export class ValidateFilter extends DesugaringStep<FilterConfigJson> {
|
|||
|
||||
export class DetectDuplicateFilters extends DesugaringStep<{
|
||||
layers: LayerConfigJson[]
|
||||
themes: LayoutConfigJson[]
|
||||
themes: ThemeConfigJson[]
|
||||
}> {
|
||||
constructor() {
|
||||
super(
|
||||
|
@ -916,15 +916,15 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
|||
}
|
||||
|
||||
convert(
|
||||
json: { layers: LayerConfigJson[]; themes: LayoutConfigJson[] },
|
||||
json: { layers: LayerConfigJson[]; themes: ThemeConfigJson[] },
|
||||
context: ConversionContext,
|
||||
): { layers: LayerConfigJson[]; themes: LayoutConfigJson[] } {
|
||||
): { layers: LayerConfigJson[]; themes: ThemeConfigJson[] } {
|
||||
const { layers, themes } = json
|
||||
const perOsmTag = new Map<
|
||||
string,
|
||||
{
|
||||
layer: LayerConfigJson
|
||||
layout: LayoutConfigJson | undefined
|
||||
theme: ThemeConfigJson | undefined
|
||||
filter: FilterConfigJson
|
||||
}[]
|
||||
>()
|
||||
|
@ -955,10 +955,10 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
|||
return
|
||||
}
|
||||
let msg = "Possible duplicate filter: " + key
|
||||
for (const { filter, layer, layout } of value) {
|
||||
for (const { filter, layer, theme } of value) {
|
||||
let id = ""
|
||||
if (layout !== undefined) {
|
||||
id = layout.id + ":"
|
||||
if (theme !== undefined) {
|
||||
id = theme.id + ":"
|
||||
}
|
||||
msg += `\n - ${id}${layer.id}.${filter.id}`
|
||||
}
|
||||
|
@ -977,11 +977,11 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
|||
string,
|
||||
{
|
||||
layer: LayerConfigJson
|
||||
layout: LayoutConfigJson | undefined
|
||||
theme: ThemeConfigJson | undefined
|
||||
filter: FilterConfigJson
|
||||
}[]
|
||||
>,
|
||||
layout?: LayoutConfigJson | undefined,
|
||||
theme?: ThemeConfigJson | undefined,
|
||||
): void {
|
||||
if (layer.filter === undefined || layer.filter === null) {
|
||||
return
|
||||
|
@ -1009,14 +1009,14 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
|||
perOsmTag.get(key).push({
|
||||
layer,
|
||||
filter,
|
||||
layout,
|
||||
theme,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class DetectDuplicatePresets extends DesugaringStep<LayoutConfig> {
|
||||
export class DetectDuplicatePresets extends DesugaringStep<ThemeConfig> {
|
||||
constructor() {
|
||||
super(
|
||||
"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 enNames = presets.map((p) => p.title.textFor("en"))
|
||||
|
@ -1074,7 +1074,7 @@ export class DetectDuplicatePresets extends DesugaringStep<LayoutConfig> {
|
|||
}
|
||||
|
||||
export class ValidateThemeEnsemble extends Conversion<
|
||||
LayoutConfig[],
|
||||
ThemeConfig[],
|
||||
Map<
|
||||
string,
|
||||
{
|
||||
|
@ -1093,7 +1093,7 @@ export class ValidateThemeEnsemble extends Conversion<
|
|||
}
|
||||
|
||||
convert(
|
||||
json: LayoutConfig[],
|
||||
json: ThemeConfig[],
|
||||
context: ConversionContext,
|
||||
): Map<
|
||||
string,
|
||||
|
|
|
@ -62,7 +62,7 @@ export default class FilterConfig {
|
|||
const fields: { name: string; type: ValidatorType }[] = (option.fields ?? []).map((f, i) => {
|
||||
const type = <ValidatorType> f.type ?? "regex"
|
||||
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
|
||||
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.
|
||||
*/
|
||||
export interface LayoutConfigJson {
|
||||
export interface ThemeConfigJson {
|
||||
/**
|
||||
* question: What is the id of this layout?
|
||||
*
|
|
@ -1,5 +1,5 @@
|
|||
import { Translation } from "../../UI/i18n/Translation"
|
||||
import { LayoutConfigJson } from "./Json/LayoutConfigJson"
|
||||
import { ThemeConfigJson } from "./Json/ThemeConfigJson"
|
||||
import LayerConfig from "./LayerConfig"
|
||||
import { LayerConfigJson } from "./Json/LayerConfigJson"
|
||||
import Constants from "../Constants"
|
||||
|
@ -13,7 +13,7 @@ import { Translatable } from "./Json/Translatable"
|
|||
/**
|
||||
* Minimal information about a theme
|
||||
**/
|
||||
export class MinimalLayoutInformation {
|
||||
export class MinimalThemeInformation {
|
||||
id: string
|
||||
icon: string
|
||||
title: Translatable
|
||||
|
@ -27,7 +27,7 @@ export class MinimalLayoutInformation {
|
|||
/**
|
||||
* Minimal information about a theme
|
||||
**/
|
||||
export class LayoutInformation {
|
||||
export class ThemeInformation {
|
||||
id: string
|
||||
icon: string
|
||||
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 readonly id: string
|
||||
public readonly credits?: string
|
||||
|
@ -57,7 +57,6 @@ export default class LayoutConfig implements LayoutInformation {
|
|||
public readonly startZoom: number
|
||||
public readonly startLat: number
|
||||
public readonly startLon: number
|
||||
public widenFactor: number
|
||||
public defaultBackgroundId?: string
|
||||
public layers: LayerConfig[]
|
||||
public tileLayerSources: (RasterLayerProperties & { defaultState?: true | boolean })[]
|
||||
|
@ -92,11 +91,11 @@ export default class LayoutConfig implements LayoutInformation {
|
|||
public readonly definitionRaw?: string
|
||||
|
||||
private readonly layersDict: Map<string, LayerConfig>
|
||||
private readonly source: LayoutConfigJson
|
||||
private readonly source: ThemeConfigJson
|
||||
public readonly enableCache: boolean
|
||||
|
||||
constructor(
|
||||
json: LayoutConfigJson,
|
||||
json: ThemeConfigJson,
|
||||
official = true,
|
||||
options?: {
|
||||
definedAtUrl?: string
|
||||
|
@ -167,7 +166,7 @@ export default class LayoutConfig implements LayoutInformation {
|
|||
? undefined
|
||||
: new Translation(json.descriptionTail, "themes:" + context + ".descriptionTail")
|
||||
this.icon = json.icon
|
||||
this.socialImage = json.socialImage ?? LayoutConfig.defaultSocialImage
|
||||
this.socialImage = json.socialImage ?? ThemeConfig.defaultSocialImage
|
||||
if (this.socialImage === "") {
|
||||
if (official) {
|
||||
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.startLat = json.startLat
|
||||
this.startLon = json.startLon
|
||||
this.widenFactor = 1.5
|
||||
|
||||
this.defaultBackgroundId = json.defaultBackgroundId
|
||||
this.tileLayerSources = json.tileLayerSources ?? []
|
|
@ -1,4 +1,4 @@
|
|||
import LayoutConfig from "./ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "./ThemeConfig/ThemeConfig"
|
||||
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
||||
import { Changes } from "../Logic/Osm/Changes"
|
||||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||
|
@ -18,7 +18,7 @@ import UserRelatedState from "../Logic/State/UserRelatedState"
|
|||
import LayerConfig from "./ThemeConfig/LayerConfig"
|
||||
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
|
||||
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 FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore"
|
||||
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.
|
||||
*/
|
||||
export default class ThemeViewState implements SpecialVisualizationState {
|
||||
readonly layout: LayoutConfig
|
||||
readonly theme: ThemeConfig
|
||||
readonly map: UIEventSource<MlMap>
|
||||
readonly changes: Changes
|
||||
readonly featureSwitches: FeatureSwitchState
|
||||
|
@ -104,7 +104,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
readonly fullNodeDatabase?: FullNodeDatabaseSource
|
||||
|
||||
readonly historicalUserLocations: WritableFeatureSource<Feature<Point>>
|
||||
readonly indexedFeatures: IndexedFeatureSource & LayoutSource
|
||||
readonly indexedFeatures: IndexedFeatureSource & ThemeSource
|
||||
readonly currentView: FeatureSource<Feature<Polygon>>
|
||||
readonly featuresInView: FeatureSource
|
||||
readonly favourites: FavouritesFeatureSource
|
||||
|
@ -160,9 +160,9 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
*/
|
||||
public readonly featureSummary: SummaryTileSourceRewriter
|
||||
|
||||
constructor(layout: LayoutConfig, mvtAvailableLayers: Set<string>) {
|
||||
constructor(layout: ThemeConfig, mvtAvailableLayers: Set<string>) {
|
||||
Utils.initDomPurify()
|
||||
this.layout = layout
|
||||
this.theme = layout
|
||||
this.featureSwitches = new FeatureSwitchState(layout)
|
||||
this.guistate = new MenuState(
|
||||
this.featureSwitches.featureSwitchWelcomeMessage.data,
|
||||
|
@ -218,7 +218,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
|
||||
{
|
||||
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(
|
||||
"overlay-" + rasterInfo.id,
|
||||
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
|
||||
*/
|
||||
|
||||
if (this.layout.layers.some((l) => l._needsFullNodeDatabase)) {
|
||||
if (this.theme.layers.some((l) => l._needsFullNodeDatabase)) {
|
||||
this.fullNodeDatabase = new FullNodeDatabaseSource()
|
||||
}
|
||||
|
||||
const layoutSource = new LayoutSource(
|
||||
const layoutSource = new ThemeSource(
|
||||
layout.layers,
|
||||
this.featureSwitches,
|
||||
this.mapProperties,
|
||||
|
@ -340,7 +340,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
})
|
||||
|
||||
this.lastClickObject = new LastClickFeatureSource(
|
||||
this.layout,
|
||||
this.theme,
|
||||
this.mapProperties.lastClickLocation,
|
||||
this.userRelatedState.addNewFeatureMode,
|
||||
)
|
||||
|
@ -414,7 +414,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
const storage = new SaveFeatureSourceToLocalStorage(
|
||||
this.osmConnection.Backend(),
|
||||
fs.layer.layerDef.id,
|
||||
LayoutSource.fromCacheZoomLevel,
|
||||
ThemeSource.fromCacheZoomLevel,
|
||||
fs,
|
||||
this.featureProperties,
|
||||
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) => {
|
||||
if (selected === undefined) {
|
||||
|
@ -517,8 +517,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
}
|
||||
})
|
||||
|
||||
if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
||||
Utils.LoadCustomCss(this.layout.customCss)
|
||||
if (this.theme.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
||||
Utils.LoadCustomCss(this.theme.customCss)
|
||||
}
|
||||
|
||||
Hash.hash.addCallbackAndRunD((hash) => {
|
||||
|
@ -738,11 +738,11 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
/**
|
||||
* 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 layers = this.layout.layers.filter(
|
||||
const layers = this.theme.layers.filter(
|
||||
(l) =>
|
||||
Constants.priviliged_layers.indexOf(<any>l.id) < 0 &&
|
||||
l.source.geojsonSource === undefined &&
|
||||
|
@ -796,8 +796,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
|
||||
|
||||
this.closestFeatures.registerSource(specialLayers.favourite, "favourite")
|
||||
if (this.layout?.lockLocation) {
|
||||
const bbox = new BBox(<any>this.layout.lockLocation)
|
||||
if (this.theme?.lockLocation) {
|
||||
const bbox = new BBox(<any>this.theme.lockLocation)
|
||||
this.mapProperties.maxbounds.setData(bbox)
|
||||
ShowDataLayer.showRange(
|
||||
this.map,
|
||||
|
@ -805,7 +805,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
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) {
|
||||
const params = MetaTagging.createExtraFuncParams(this)
|
||||
this.featureProperties.trackFeatureSource(specialLayers.current_view)
|
||||
|
@ -814,7 +814,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
features,
|
||||
params,
|
||||
currentViewLayer,
|
||||
this.layout,
|
||||
this.theme,
|
||||
this.osmObjectDownloader,
|
||||
this.featureProperties,
|
||||
)
|
||||
|
@ -909,9 +909,9 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
*/
|
||||
private initActors() {
|
||||
|
||||
if (!this.layout.official) {
|
||||
if (!this.theme.official) {
|
||||
// Add custom themes to the "visited custom themes"
|
||||
const th = this.layout
|
||||
const th = this.theme
|
||||
this.userRelatedState.addUnofficialTheme({
|
||||
id: th.id,
|
||||
icon: th.icon,
|
||||
|
@ -945,7 +945,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
this.selectedElement.addCallbackD(selected => {
|
||||
const [osm_type, osm_id] = selected.properties.id.split("/")
|
||||
const [lon, lat] = GeoOperations.centerpointCoordinates(selected)
|
||||
const layer = this.layout.getMatchingLayer(selected.properties)
|
||||
const layer = this.theme.getMatchingLayer(selected.properties)
|
||||
|
||||
const nameOptions = [
|
||||
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>) {
|
||||
|
||||
|
@ -1002,15 +1002,15 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
return UserRelatedState.usersettingsConfig
|
||||
}
|
||||
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")) {
|
||||
return GeocodingUtils.searchLayer
|
||||
}
|
||||
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 = "") {
|
||||
|
@ -1059,7 +1059,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
body: JSON.stringify({
|
||||
stacktrace,
|
||||
message: "" + message,
|
||||
layout: this.layout.id,
|
||||
theme: this.theme.id,
|
||||
version: Constants.vNumber,
|
||||
language: this.userRelatedState.language.data,
|
||||
username: this.osmConnection.userDetails.data?.name,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
import Constants from "../Models/Constants"
|
||||
import { ImmutableStore, Store, Stores, UIEventSource } from "../Logic/UIEventSource"
|
||||
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 LoginButton from "./Base/LoginButton.svelte"
|
||||
import Mastodon from "../assets/svg/Mastodon.svelte"
|
||||
|
@ -46,16 +46,16 @@
|
|||
|
||||
let searchIsFocused = new UIEventSource(true)
|
||||
|
||||
const officialThemes: MinimalLayoutInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === false)
|
||||
const hiddenThemes: MinimalLayoutInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === true)
|
||||
let visitedHiddenThemes: Store<MinimalLayoutInformation[]> = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection)
|
||||
const officialThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === false)
|
||||
const hiddenThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter(th => th.hideFromOverview === true)
|
||||
let visitedHiddenThemes: Store<MinimalThemeInformation[]> = UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection)
|
||||
.map((knownIds) => hiddenThemes.filter((theme) =>
|
||||
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))))
|
||||
function filtered(themes: Store<MinimalLayoutInformation[]>): Store<MinimalLayoutInformation[]> {
|
||||
function filtered(themes: Store<MinimalThemeInformation[]>): Store<MinimalThemeInformation[]> {
|
||||
return searchStable.map(search => {
|
||||
if (!search) {
|
||||
return themes.data
|
||||
|
@ -74,9 +74,9 @@
|
|||
}
|
||||
|
||||
|
||||
let officialSearched : Store<MinimalLayoutInformation[]>= filtered(new ImmutableStore(officialThemes))
|
||||
let hiddenSearched: Store<MinimalLayoutInformation[]> = filtered(visitedHiddenThemes)
|
||||
let customSearched: Store<MinimalLayoutInformation[]> = filtered(customThemes)
|
||||
let officialSearched : Store<MinimalThemeInformation[]>= filtered(new ImmutableStore(officialThemes))
|
||||
let hiddenSearched: Store<MinimalThemeInformation[]> = filtered(visitedHiddenThemes)
|
||||
let customSearched: Store<MinimalThemeInformation[]> = filtered(customThemes)
|
||||
|
||||
|
||||
let searchIsFocussed = new UIEventSource(false)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
export let state: SpecialVisualizationState
|
||||
|
||||
let layoutToUse = state.layout
|
||||
let layoutToUse = state.theme
|
||||
let iconAttributions: string[] = layoutToUse.getUsedImages()
|
||||
|
||||
const allLicenses = {}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
export let state: SpecialVisualizationState
|
||||
|
||||
const t = Translations.t.general.attribution
|
||||
const layoutToUse = state.layout
|
||||
const layoutToUse = state.theme
|
||||
|
||||
let maintainer: Translation = undefined
|
||||
if (layoutToUse.credits !== undefined && layoutToUse.credits !== "") {
|
||||
|
@ -122,7 +122,7 @@
|
|||
{/if}
|
||||
{#if maintainer !== undefined}
|
||||
<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} />
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import Icon from "../Map/Icon.svelte"
|
||||
|
||||
export let state: SpecialVisualizationState
|
||||
let theme = state.layout?.id ?? ""
|
||||
let config: ExtraLinkConfig = state.layout.extraLink
|
||||
let theme = state.theme?.id ?? ""
|
||||
let config: ExtraLinkConfig = state.theme.extraLink
|
||||
let basepath = window.location.host
|
||||
let showWelcomeMessageSwitch = state.featureSwitches.featureSwitchWelcomeMessage
|
||||
const isIframe = Utils.isIframe
|
||||
|
@ -42,7 +42,7 @@
|
|||
{#if config.text}
|
||||
<Tr t={config.text} />
|
||||
{:else}
|
||||
<Tr t={t.screenToSmall.Subs({ theme: state.layout.title })} />
|
||||
<Tr t={t.screenToSmall.Subs({ theme: state.theme.title })} />
|
||||
{/if}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
export let state: ThemeViewState
|
||||
export let onlyLink: boolean
|
||||
|
||||
let layout = state.layout
|
||||
let theme = state.theme
|
||||
|
||||
let allEnabled: boolean
|
||||
let allDisabled: boolean
|
||||
|
@ -70,7 +70,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{#each layout.layers as layer}
|
||||
{#each theme.layers as layer}
|
||||
<Filterview
|
||||
{state}
|
||||
zoomlevel={state.mapProperties.zoom}
|
||||
|
@ -79,7 +79,7 @@
|
|||
/>
|
||||
{/each}
|
||||
|
||||
{#each layout.tileLayerSources as tilesource}
|
||||
{#each theme.tileLayerSources as tilesource}
|
||||
<OverlayToggle
|
||||
layerproperties={tilesource}
|
||||
state={state.overlayLayerStates.get(tilesource.id)}
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
let usersettingslayer = new LayerConfig(<LayerConfigJson>usersettings, "usersettings", true)
|
||||
|
||||
let layout = state.layout
|
||||
let theme = state.theme
|
||||
let featureSwitches = state.featureSwitches
|
||||
let showHome = featureSwitches.featureSwitchBackToThemeOverview
|
||||
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 -->
|
||||
<LoginToggle {state}>
|
||||
<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} />
|
||||
<LoginButton clss="primary" osmConnection={state.osmConnection} />
|
||||
</div>
|
||||
|
@ -161,12 +161,12 @@
|
|||
|
||||
<Page {onlyLink} shown={pg.about_theme}>
|
||||
<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} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="header">
|
||||
<Marker size="h-8 w-8 mr-3" icons={layout.icon} />
|
||||
<Tr t={layout.title} />
|
||||
<Marker size="h-8 w-8 mr-3" icons={theme.icon} />
|
||||
<Tr t={theme.title} />
|
||||
</svelte:fragment>
|
||||
<ThemeIntroPanel {state} />
|
||||
</Page>
|
||||
|
@ -193,25 +193,25 @@
|
|||
</Page>
|
||||
{/if}
|
||||
|
||||
{#if layout.official}
|
||||
{#if theme.official}
|
||||
<a
|
||||
class="flex"
|
||||
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
|
||||
layout.id +
|
||||
theme.id +
|
||||
".md"}
|
||||
target="_blank"
|
||||
>
|
||||
<DocumentMagnifyingGlass class="h-6 w-6" />
|
||||
<Tr
|
||||
t={Translations.t.general.attribution.openThemeDocumentation.Subs({
|
||||
name: layout.title,
|
||||
name: theme.title,
|
||||
})}
|
||||
/>
|
||||
</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" />
|
||||
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: layout.title })} />
|
||||
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: theme.title })} />
|
||||
</a>
|
||||
{/if}
|
||||
</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?...`
|
||||
* Note that the 'layout='-param will be included automatically
|
||||
*/
|
||||
let needsThemeRedirect = url.port !== "" || url.hostname.match(/^[0-9]/) || !state.layout.official
|
||||
let layoutId = state.layout.id
|
||||
let needsThemeRedirect = url.port !== "" || url.hostname.match(/^[0-9]/) || !state.theme.official
|
||||
let layoutId = state.theme.id
|
||||
let baseLink = `${url.protocol}//${url.host}/${needsThemeRedirect ? "theme.html" : layoutId}?`
|
||||
|
||||
let showWelcomeMessage = true
|
||||
|
@ -44,7 +44,7 @@
|
|||
enableBackground: boolean,
|
||||
enableGeolocation: boolean
|
||||
) {
|
||||
const layout = state.layout
|
||||
const layout = state.theme
|
||||
let excluded = Utils.NoNull([
|
||||
showWelcomeMessage ? undefined : "fs-welcome-message",
|
||||
enableLogin ? undefined : "fs-enable-login",
|
||||
|
@ -99,7 +99,7 @@
|
|||
${
|
||||
enableGeolocation ? 'allow="geolocation"' : ""
|
||||
} 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>`
|
||||
|
||||
Array.from(state.layerState.filteredLayers.values()).forEach((flayer) =>
|
||||
|
@ -163,7 +163,7 @@
|
|||
<Tr t={tr.stateIsIncluded} />
|
||||
<a
|
||||
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} />
|
||||
</a>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
export let i: number = undefined
|
||||
let id = feature.properties.id
|
||||
let tags = state.featureProperties.getStore(id)
|
||||
let layer: LayerConfig = state.layout.getMatchingLayer(tags.data)
|
||||
let layer: LayerConfig = state.theme.getMatchingLayer(tags.data)
|
||||
</script>
|
||||
|
||||
<span class="inline-flex gap-x-1">
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { ImmutableStore, Store } from "../../Logic/UIEventSource"
|
||||
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 Translations from "../i18n/Translations"
|
||||
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://")
|
||||
export let state: { layoutToUse?: { id: string }; osmConnection: OsmConnection }
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* The theme introduction panel
|
||||
*/
|
||||
export let state: ThemeViewState
|
||||
let layout = state.layout
|
||||
let theme = state.theme
|
||||
|
||||
let geolocation = state.geolocation.geolocationState
|
||||
let geopermission: Store<GeolocationPermissionState> = geolocation.permission
|
||||
|
@ -42,16 +42,16 @@
|
|||
<div>
|
||||
<!-- Intro, description, ... -->
|
||||
|
||||
<Tr t={layout.description} />
|
||||
<Tr t={theme.description} />
|
||||
|
||||
<If condition={state.featureSwitches.featureSwitchEnableLogin}>
|
||||
<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} />
|
||||
{/if}
|
||||
</If>
|
||||
|
||||
<Tr t={layout.descriptionTail} />
|
||||
<Tr t={theme.descriptionTail} />
|
||||
|
||||
<!-- Buttons: open map, go to location, search -->
|
||||
<NextButton
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import ThemeButton from "./ThemeButton.svelte"
|
||||
import { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
|
||||
export let search: UIEventSource<string>
|
||||
export let themes: MinimalLayoutInformation[]
|
||||
export let themes: MinimalThemeInformation[]
|
||||
export let state: { osmConnection: OsmConnection }
|
||||
|
||||
export let hasSelection : boolean = true
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import Translations from "../i18n/Translations"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import Invalid from "../../assets/svg/Invalid.svelte"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
|
@ -17,7 +17,7 @@
|
|||
|
||||
export let trace: (title: string) => string
|
||||
export let state: {
|
||||
layout: LayoutConfig
|
||||
layout: ThemeConfig
|
||||
osmConnection: OsmConnection
|
||||
readonly featureSwitchUserbadge: Store<boolean>
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
new Tag(key, externalProperties[key]),
|
||||
tags.data,
|
||||
{
|
||||
theme: state.layout.id,
|
||||
theme: state.theme.id,
|
||||
changeType: "import",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
currentStep = "applying_all"
|
||||
const tagsToApply = missing.data.map((k) => new Tag(k, externalProperties[k]))
|
||||
const change = new ChangeTagAction(tags.data.id, new And(tagsToApply), tags.data, {
|
||||
theme: state.layout.id,
|
||||
theme: state.theme.id,
|
||||
changeType: "import",
|
||||
})
|
||||
await state.changes.applyChanges(await change.CreateChangeDescriptions())
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
const gpsIsDisplayed = gpsLayer.isDisplayed.data
|
||||
try {
|
||||
gpsLayer.isDisplayed.setData(false)
|
||||
const name = state.layout.id
|
||||
const name = state.theme.id
|
||||
|
||||
const title = `MapComplete_${name}_export_${new Date()
|
||||
.toISOString()
|
||||
|
|
|
@ -156,7 +156,7 @@ export default class DownloadHelper {
|
|||
private getCleanGeoJsonPerLayer(includeMetaData: boolean): Map<string, Feature[]> {
|
||||
const state = this._state
|
||||
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
|
||||
|
||||
for (const neededLayer of neededLayers) {
|
||||
|
@ -186,7 +186,7 @@ export default class DownloadHelper {
|
|||
createImage(key: string, width: string, height: string): HTMLImageElement {
|
||||
const img = document.createElement("img")
|
||||
const sources = {
|
||||
layouticon: this._state.layout.icon,
|
||||
layouticon: this._state.theme.icon,
|
||||
}
|
||||
img.src = sources[key]
|
||||
if (!img.src) {
|
||||
|
|
|
@ -38,10 +38,10 @@
|
|||
return downloadHelper.createImage(key, width, height)
|
||||
},
|
||||
textSubstitutions: <Record<string, string | Translation>>{
|
||||
"layout.title": state.layout.title,
|
||||
layoutid: state.layout.id,
|
||||
title: state.layout.title,
|
||||
layoutImg: state.layout.icon,
|
||||
"layout.title": state.theme.title,
|
||||
layoutid: state.theme.id,
|
||||
title: state.theme.title,
|
||||
layoutImg: state.theme.icon,
|
||||
version: Constants.vNumber,
|
||||
date: new Date().toISOString().substring(0, 16),
|
||||
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 { Changes } from "../../Logic/Osm/Changes"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import Delete_icon from "../../assets/svg/Delete_icon.svelte"
|
||||
|
||||
|
@ -14,7 +14,7 @@ export default class DeleteImage extends Toggle {
|
|||
constructor(
|
||||
key: string,
|
||||
tags: Store<any>,
|
||||
state: { layout: LayoutConfig; changes?: Changes; osmConnection?: OsmConnection }
|
||||
state: { theme: ThemeConfig; changes?: Changes; osmConnection?: OsmConnection }
|
||||
) {
|
||||
const oldValue = tags.data[key]
|
||||
const isDeletedBadge = Translations.t.image.isDeleted
|
||||
|
@ -25,7 +25,7 @@ export default class DeleteImage extends Toggle {
|
|||
await state?.changes?.applyAction(
|
||||
new ChangeTagAction(tags.data.id, new Tag(key, oldValue), tags.data, {
|
||||
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(
|
||||
new ChangeTagAction(tags.data.id, new Tag(key, ""), tags.data, {
|
||||
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 { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import { Changes } from "../../Logic/Osm/Changes"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import AttributedImage from "./AttributedImage.svelte"
|
||||
|
||||
|
@ -18,7 +18,7 @@ export class ImageCarousel extends Toggle {
|
|||
state: {
|
||||
osmConnection?: OsmConnection
|
||||
changes?: Changes
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
previewedImage?: UIEventSource<ProvidedImage>
|
||||
}
|
||||
) {
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
const url = targetValue
|
||||
if (isLinked) {
|
||||
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"
|
||||
})
|
||||
await state.changes.applyAction(action)
|
||||
|
@ -54,7 +54,7 @@
|
|||
const v = currentTags[k]
|
||||
if (v === url) {
|
||||
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"
|
||||
})
|
||||
state.changes.applyAction(action)
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
ShowDataLayer.showMultipleLayers(
|
||||
map,
|
||||
new StaticFeatureSource([feature]),
|
||||
state.layout.layers,
|
||||
state.theme.layers,
|
||||
)
|
||||
|
||||
onDestroy(
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
const maproulette_id = tags.data[maproulette_id_key] ?? tags.data.mr_taskId ?? tags.data.id
|
||||
try {
|
||||
await Maproulette.singleton.closeTask(Number(maproulette_id), Number(statusToSet), {
|
||||
tags: `MapComplete MapComplete:${state.layout.id}`,
|
||||
tags: `MapComplete MapComplete:${state.theme.id}`,
|
||||
comment: feedback,
|
||||
})
|
||||
tags.data["mr_taskStatus"] = Maproulette.STATUS_MEANING[Number(statusToSet)]
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
}
|
||||
|
||||
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
||||
theme: state.layout?.id ?? "unkown",
|
||||
theme: state.theme?.id ?? "unkown",
|
||||
changeType: "create",
|
||||
snapOnto: snapToWay,
|
||||
reusePointWithinMeters: 1,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import type PresetConfig from "../../../Models/ThemeConfig/PresetConfig"
|
||||
import Tr from "../../Base/Tr.svelte"
|
||||
|
@ -19,7 +19,7 @@
|
|||
* This component lists all the presets and allows the user to select one
|
||||
*/
|
||||
export let state: SpecialVisualizationState
|
||||
let layout: LayoutConfig = state.layout
|
||||
let layout: ThemeConfig = state.theme
|
||||
let presets: {
|
||||
preset: PresetConfig
|
||||
layer: LayerConfig
|
||||
|
|
|
@ -10,7 +10,7 @@ import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeature
|
|||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import Loading from "../Base/Loading"
|
||||
import Translations from "../i18n/Translations"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import { Changes } from "../../Logic/Osm/Changes"
|
||||
import { UIElement } from "../UIElement"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
|
@ -32,7 +32,7 @@ export interface AutoAction extends SpecialVisualization {
|
|||
applyActionOn(
|
||||
feature: Feature,
|
||||
state: {
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
},
|
||||
|
@ -282,7 +282,7 @@ export default class AutoApplyButton implements SpecialVisualization {
|
|||
argument: string[]
|
||||
): BaseUIElement {
|
||||
try {
|
||||
if (!state.layout.official && !state.featureSwitchIsTesting.data) {
|
||||
if (!state.theme.official && !state.featureSwitchIsTesting.data) {
|
||||
const t = Translations.t.general.add.import
|
||||
return new Combine([
|
||||
new FixedUiElement(
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
featureId,
|
||||
deleteConfig.softDeletionTags,
|
||||
{
|
||||
theme: state?.layout?.id ?? "unknown",
|
||||
theme: state?.theme?.id ?? "unknown",
|
||||
specialMotivation: deleteReason,
|
||||
},
|
||||
canBeDeleted.data
|
||||
|
@ -73,7 +73,7 @@
|
|||
} else {
|
||||
// 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, {
|
||||
theme: state?.layout?.id ?? "unkown",
|
||||
theme: state?.theme?.id ?? "unkown",
|
||||
changeType: "special-delete",
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization"
|
||||
import { UIEventSource } from "../../../Logic/UIEventSource"
|
||||
import { Feature, Geometry, LineString, Polygon } from "geojson"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import BaseUIElement from "../../BaseUIElement"
|
||||
import { ImportFlowArguments, ImportFlowUtils } from "./ImportFlow"
|
||||
import Translations from "../../i18n/Translations"
|
||||
|
@ -12,7 +11,7 @@ import ConflateImportFlowState from "./ConflateImportFlowState"
|
|||
import { AutoAction } from "../AutoApplyButton"
|
||||
import { IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
||||
import { Changes } from "../../../Logic/Osm/Changes"
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||
import { OsmConnection } from "../../../Logic/Osm/OsmConnection"
|
||||
|
||||
export interface ConflateFlowArguments extends ImportFlowArguments {
|
||||
|
@ -47,7 +46,7 @@ export default class ConflateImportButtonViz implements SpecialVisualization, Au
|
|||
feature: Feature<Geometry, { [name: string]: any }>,
|
||||
state: {
|
||||
osmConnection: OsmConnection
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
},
|
||||
|
|
|
@ -10,7 +10,7 @@ import { GeoOperations } from "../../../Logic/GeoOperations"
|
|||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||
import { MergePointConfig } from "../../../Logic/Osm/Actions/CreateWayWithPointReuseAction"
|
||||
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 { FeatureSource, IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
||||
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
@ -61,7 +61,7 @@ export default class ConflateImportFlowState extends ImportFlow<ConflateFlowArgu
|
|||
args: ConflateFlowArguments,
|
||||
state: {
|
||||
osmConnection: OsmConnection
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
|
@ -88,7 +88,7 @@ export default class ConflateImportFlowState extends ImportFlow<ConflateFlowArgu
|
|||
GeoOperations.removeOvernoding(feature),
|
||||
idOfFeatureToReplaceGeometry,
|
||||
{
|
||||
theme: state.layout.id,
|
||||
theme: state.theme.id,
|
||||
newTags: tagsToApply.data,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -174,7 +174,7 @@ export default abstract class ImportFlow<ArgT extends ImportFlowArguments> {
|
|||
return { error: t.hasBeenImported }
|
||||
}
|
||||
|
||||
if (!state.layout.official && !isTesting) {
|
||||
if (!state.theme.official && !isTesting) {
|
||||
// Unofficial theme - imports not allowed
|
||||
return {
|
||||
error: t.officialThemesOnly,
|
||||
|
@ -183,7 +183,7 @@ export default abstract class ImportFlow<ArgT extends ImportFlowArguments> {
|
|||
}
|
||||
|
||||
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)
|
||||
return { error: new Translation({ "*": e }) }
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// The following variables are used for the map
|
||||
const targetLayers: LayerConfig[] = args.targetLayer
|
||||
.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 =
|
||||
args.snap_onto_layers?.split(",")?.map((l) => l.trim()) ?? []
|
||||
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, {
|
||||
theme: this.state.layout.id,
|
||||
theme: this.state.theme.id,
|
||||
changeType: "import",
|
||||
snapOnto: <OsmWay>snapOnto,
|
||||
specialMotivation: specialMotivation,
|
||||
|
|
|
@ -10,7 +10,7 @@ import { FixedUiElement } from "../../Base/FixedUiElement"
|
|||
import WayImportFlow from "./WayImportFlow.svelte"
|
||||
import WayImportFlowState, { WayImportFlowArguments } from "./WayImportFlowState"
|
||||
import { Utils } from "../../../Utils"
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
|
||||
import { Changes } from "../../../Logic/Osm/Changes"
|
||||
import { IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
||||
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
@ -87,7 +87,7 @@ export default class WayImportButtonViz implements AutoAction, SpecialVisualizat
|
|||
public async applyActionOn(
|
||||
feature: Feature,
|
||||
state: {
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase: FullNodeDatabaseSource
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
ShowDataLayer.showMultipleLayers(
|
||||
map,
|
||||
new StaticFeatureSource([importFlow.originalFeature]),
|
||||
state.layout.layers,
|
||||
state.theme.layers,
|
||||
{ zoomToFeatures: false }
|
||||
)
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
|||
import { OsmCreateAction, PreviewableAction } from "../../../Logic/Osm/Actions/OsmChangeAction"
|
||||
import { FeatureSource, IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
|
||||
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 FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
||||
|
@ -52,7 +52,7 @@ export default class WayImportFlowState extends ImportFlow<WayImportFlowArgument
|
|||
feature: Feature<LineString | Polygon>,
|
||||
args: WayImportFlowArguments,
|
||||
state: {
|
||||
layout: LayoutConfig
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
} else if (state.changes) {
|
||||
await state.changes.applyAction(
|
||||
new ChangeTagAction(tags.data.id, new And(selection), tags.data, {
|
||||
theme: state?.layout?.id ?? "unkown",
|
||||
theme: state?.theme?.id ?? "unkown",
|
||||
changeType: "answer",
|
||||
})
|
||||
)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
const t = Translations.t.favouritePoi
|
||||
|
||||
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>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
const t = Translations.t.favouritePoi
|
||||
|
||||
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>
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
ShowDataLayer.showMultipleLayers(
|
||||
mlmap,
|
||||
new StaticFeatureSource(featuresToShow),
|
||||
state.layout.layers,
|
||||
state.theme.layers,
|
||||
{ zoomToFeatures: true }
|
||||
)
|
||||
</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 matchingPreset = matchingPresets.flatMap(pr => pr.preciseInput?.snapToLayers)
|
||||
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)
|
||||
reasons.push({
|
||||
text,
|
||||
|
@ -133,7 +133,7 @@ export class MoveWizardState {
|
|||
snappedTo,
|
||||
{
|
||||
reason: reason.changesetCommentValue,
|
||||
theme: state.layout.id,
|
||||
theme: state.theme.id,
|
||||
}),
|
||||
)
|
||||
featureToMove.properties._lat = loc.lat
|
||||
|
@ -152,7 +152,7 @@ export class MoveWizardState {
|
|||
featureToMove.properties,
|
||||
{
|
||||
changeType: "relocated",
|
||||
theme: state.layout.id,
|
||||
theme: state.theme.id,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
|
@ -64,7 +64,7 @@ class MultiApplyExecutor {
|
|||
const keysToChange = this.params.keysToApply
|
||||
const overwrite = this.params.overwrite
|
||||
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) {
|
||||
const tagsToApply: Tag[] = []
|
||||
const otherFeatureTags = allElements.getStore(id).data
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
return
|
||||
}
|
||||
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)
|
||||
console.log("Created a note, got id", id)
|
||||
const feature = <Feature<Point, OsmTags>>{
|
||||
|
|
|
@ -49,7 +49,7 @@ export class PlantNetDetectionViz implements SpecialVisualization {
|
|||
]),
|
||||
tags.data,
|
||||
{
|
||||
theme: state.layout.id,
|
||||
theme: state.theme.id,
|
||||
changeType: "plantnet-ai-detection",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
let [lon, lat] = GeoOperations.centerpointCoordinates(feature)
|
||||
|
||||
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 url = id.mapD(
|
||||
(id) =>
|
||||
|
|
|
@ -30,9 +30,9 @@ export class ShareLinkViz implements SpecialVisualization {
|
|||
const text = args[1]
|
||||
|
||||
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 =
|
||||
matchingLayer?.title?.GetRenderValue(tagSource.data)?.Subs(tagSource.data)?.txt ??
|
||||
tagSource.data?.name ??
|
||||
|
@ -49,7 +49,7 @@ export class ShareLinkViz implements SpecialVisualization {
|
|||
return {
|
||||
title: name,
|
||||
url: url,
|
||||
text: state?.layout?.shortDescription?.txt ?? "MapComplete",
|
||||
text: state?.theme?.shortDescription?.txt ?? "MapComplete",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
id,
|
||||
splitPoints.data.map((ff) => <[number, number]>(<Point>ff.geometry).coordinates),
|
||||
{
|
||||
theme: state?.layout?.id,
|
||||
theme: state?.theme?.id,
|
||||
},
|
||||
5
|
||||
)
|
||||
|
|
|
@ -144,7 +144,7 @@ export default class TagApplyButton implements AutoAction, SpecialVisualization
|
|||
new And(tagsToApply.data),
|
||||
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",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -283,7 +283,7 @@
|
|||
}
|
||||
dispatch("saved", { config, applied: selectedTags })
|
||||
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",
|
||||
})
|
||||
freeformInput.set(undefined)
|
||||
|
@ -327,7 +327,7 @@
|
|||
function clearAnswer() {
|
||||
const tagsToSet = settableKeys.data.map(k => new Tag(k, ""))
|
||||
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",
|
||||
})
|
||||
freeformInput.set(undefined)
|
||||
|
|
|
@ -5,7 +5,7 @@ import List from "./Base/List"
|
|||
import Translations from "./i18n/Translations"
|
||||
import { QueryParameters } from "../Logic/Web/QueryParameters"
|
||||
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 MarkdownUtils from "../Utils/MarkdownUtils"
|
||||
|
||||
|
@ -27,7 +27,7 @@ export default class QueryParameterDocumentation {
|
|||
]
|
||||
|
||||
public static UrlParamDocs(): Map<string, string> {
|
||||
const dummyLayout = new LayoutConfig(<any>{
|
||||
const dummyLayout = new ThemeConfig(<any>{
|
||||
id: ">theme<",
|
||||
title: { en: "<theme>" },
|
||||
description: "A theme to generate docs with",
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
let tags: UIEventSource<Record<string, string>>
|
||||
let descriptionTr: TagRenderingConfig = undefined
|
||||
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)
|
||||
descriptionTr = layer?.tagRenderings?.find(tr => tr.labels.indexOf("description") >= 0)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import Icon from "../Map/Icon.svelte"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import ThemeSearch from "../../Logic/Search/ThemeSearch"
|
||||
|
||||
export let entry: MinimalLayoutInformation
|
||||
export let entry: MinimalThemeInformation
|
||||
let otherTheme = entry
|
||||
</script>
|
||||
{#if entry}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
export let state: SpecialVisualizationState
|
||||
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
|
||||
|
||||
const t =Translations.t.general.search
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||
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 { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||
import { Changes } from "../Logic/Osm/Changes"
|
||||
|
@ -19,7 +19,7 @@ import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFe
|
|||
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
|
||||
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
|
||||
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 ShowDataLayer from "./Map/ShowDataLayer"
|
||||
import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch"
|
||||
|
@ -33,13 +33,13 @@ import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropert
|
|||
*/
|
||||
export interface SpecialVisualizationState {
|
||||
readonly guistate: MenuState
|
||||
readonly layout: LayoutConfig
|
||||
readonly theme: ThemeConfig
|
||||
readonly featureSwitches: FeatureSwitchState
|
||||
|
||||
readonly layerState: LayerState
|
||||
readonly featureProperties: FeaturePropertiesStore
|
||||
|
||||
readonly indexedFeatures: IndexedFeatureSource & LayoutSource
|
||||
readonly indexedFeatures: IndexedFeatureSource & ThemeSource
|
||||
/**
|
||||
* Some features will create a new element that should be displayed.
|
||||
* 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][] = []
|
||||
for (const layerAndTagRenderingId of layerAndtagRenderingIds.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)
|
||||
tagRenderings.push([layer, tagRendering])
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ export default class SpecialVisualizations {
|
|||
Locale.showLinkToWeblate.map((showTranslations) => {
|
||||
const languages = showTranslations
|
||||
? LanguageUtils.usedLanguagesSorted
|
||||
: state.layout.language
|
||||
: state.theme.language
|
||||
return new SvelteUIElement(LanguagePicker, {
|
||||
assignTo: state.userRelatedState.language,
|
||||
availableLanguages: languages,
|
||||
|
@ -971,7 +971,7 @@ export default class SpecialVisualizations {
|
|||
return undefined
|
||||
}
|
||||
const allUnits: Unit[] = [].concat(
|
||||
...(state?.layout?.layers?.map((lyr) => lyr.units) ?? [])
|
||||
...(state?.theme?.layers?.map((lyr) => lyr.units) ?? [])
|
||||
)
|
||||
const unit = allUnits.filter((unit) =>
|
||||
unit.isApplicableToKey(key)
|
||||
|
@ -1125,7 +1125,7 @@ export default class SpecialVisualizations {
|
|||
) =>
|
||||
new VariableUiElement(
|
||||
tagsSource.map((tags) => {
|
||||
if (state.layout === undefined) {
|
||||
if (state.theme === undefined) {
|
||||
return "<feature title>"
|
||||
}
|
||||
const title = layer?.title?.GetRenderValue(tags)
|
||||
|
@ -1276,7 +1276,7 @@ export default class SpecialVisualizations {
|
|||
|
||||
constr: (state) => {
|
||||
return new Combine(
|
||||
state.layout.layers
|
||||
state.theme.layers
|
||||
.filter(
|
||||
(l) =>
|
||||
l.name !== null &&
|
||||
|
@ -1995,7 +1995,7 @@ export default class SpecialVisualizations {
|
|||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const translation = tagSource.map((tags) => {
|
||||
const layer = state.layout.getMatchingLayer(tags)
|
||||
const layer = state.theme.getMatchingLayer(tags)
|
||||
return layer?.getMostMatchingPreset(tags)?.description
|
||||
})
|
||||
return new VariableUiElement(translation)
|
||||
|
|
|
@ -11,7 +11,7 @@ import BaseUIElement from "./BaseUIElement"
|
|||
import Title from "./Base/Title"
|
||||
import { FixedUiElement } from "./Base/FixedUiElement"
|
||||
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 SvelteUIElement from "./Base/SvelteUIElement"
|
||||
import Filterview from "./BigComponents/Filterview.svelte"
|
||||
|
@ -24,7 +24,7 @@ import { Feature } from "geojson"
|
|||
class StatsticsForOverviewFile extends Combine {
|
||||
constructor(homeUrl: string, paths: string[]) {
|
||||
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 filterPanel = new Combine([
|
||||
new Title("Filters"),
|
||||
|
|
|
@ -18,7 +18,7 @@ import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
|||
import { OsmTags } from "../../Models/OsmFeature"
|
||||
import { Feature, Point } from "geojson"
|
||||
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 { ConversionContext } from "../../Models/ThemeConfig/Conversion/ConversionContext"
|
||||
import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource"
|
||||
|
@ -334,7 +334,7 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
|
|||
return 0
|
||||
}
|
||||
}
|
||||
public readonly layout: { getMatchingLayer: (key: any) => LayerConfig }
|
||||
public readonly theme: { getMatchingLayer: (key: any) => LayerConfig }
|
||||
public readonly featureSwitches: {
|
||||
featureSwitchIsDebugging: UIEventSource<boolean>
|
||||
}
|
||||
|
@ -359,7 +359,7 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
|
|||
options: { expertMode: UIEventSource<boolean> }
|
||||
) {
|
||||
super(schema, server, "layers", osmConnection, options)
|
||||
this.layout = {
|
||||
this.theme = {
|
||||
getMatchingLayer: () => {
|
||||
try {
|
||||
return new LayerConfig(<LayerConfigJson>this.configuration.data, "dynamic")
|
||||
|
@ -458,7 +458,8 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
|
|||
}
|
||||
const state: DesugaringContext = {
|
||||
tagRenderings: sharedQuestions,
|
||||
sharedLayers: layers
|
||||
sharedLayers: layers,
|
||||
tagRenderingOrder: []
|
||||
}
|
||||
const prepare = this.buildValidation(state)
|
||||
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(
|
||||
schema: ConfigMeta[],
|
||||
server: StudioServer,
|
||||
|
@ -483,7 +484,7 @@ export class EditThemeState extends EditJsonState<LayoutConfigJson> {
|
|||
this.setupFixers()
|
||||
}
|
||||
|
||||
protected buildValidation(state: DesugaringContext): Conversion<LayoutConfigJson, any> {
|
||||
protected buildValidation(state: DesugaringContext): Conversion<ThemeConfigJson, any> {
|
||||
return new Pipe(
|
||||
new PrevalidateTheme(),
|
||||
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()
|
||||
|
||||
for (const l of configuration.layers ?? []) {
|
||||
|
@ -534,7 +535,8 @@ export class EditThemeState extends EditJsonState<LayoutConfigJson> {
|
|||
}
|
||||
const state: DesugaringContext = {
|
||||
tagRenderings: sharedQuestions,
|
||||
sharedLayers: layers
|
||||
sharedLayers: layers,
|
||||
tagRenderingOrder: []
|
||||
}
|
||||
const prepare = this.buildValidation(state)
|
||||
const context = ConversionContext.construct([], ["prepare"])
|
||||
|
@ -542,7 +544,7 @@ export class EditThemeState extends EditJsonState<LayoutConfigJson> {
|
|||
Utils.NoNullInplace(configuration.layers)
|
||||
}
|
||||
try {
|
||||
prepare.convert(<LayoutConfigJson>configuration, context)
|
||||
prepare.convert(<ThemeConfigJson>configuration, context)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
context.err(e)
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Utils } from "../../Utils"
|
|||
import Constants from "../../Models/Constants"
|
||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
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.
|
||||
|
@ -71,12 +71,12 @@ export default class StudioServer {
|
|||
}
|
||||
|
||||
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(
|
||||
layerId: string,
|
||||
category: "layers" | "themes",
|
||||
uid?: number
|
||||
): Promise<LayerConfigJson | LayoutConfigJson> {
|
||||
): Promise<LayerConfigJson | ThemeConfigJson> {
|
||||
try {
|
||||
return <any>await Utils.downloadJson(this.urlFor(layerId, category, uid))
|
||||
} catch (e) {
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
export let state: ThemeViewState
|
||||
|
||||
|
||||
let layout = state.layout
|
||||
let theme = state.theme
|
||||
let maplibremap: UIEventSource<MlMap> = state.map
|
||||
let state_selectedElement = state.selectedElement
|
||||
let selectedElement: UIEventSource<Feature> = new UIEventSource<Feature>(undefined)
|
||||
|
@ -65,7 +65,7 @@
|
|||
let gpsButtonAriaLabel = state.geolocation.geolocationState.gpsStateExplanation
|
||||
let debug = state.featureSwitches.featureSwitchIsDebugging
|
||||
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 currentZoom = state.mapProperties.zoom
|
||||
let showCrosshair = state.userRelatedState.showCrosshair
|
||||
|
@ -213,7 +213,7 @@
|
|||
<div class="flex w-full items-end justify-between px-4">
|
||||
<div class="flex flex-col">
|
||||
<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
|
||||
class="low-interaction pointer-events-auto w-fit"
|
||||
class:disabled={$currentZoom < Constants.minZoomLevelToAddNewPoint}
|
||||
|
@ -224,7 +224,7 @@
|
|||
>
|
||||
{#if $currentZoom < Constants.minZoomLevelToAddNewPoint}
|
||||
<Tr t={Translations.t.general.add.zoomInFurther} />
|
||||
{:else if state.layout.hasPresets()}
|
||||
{:else if state.theme.hasPresets()}
|
||||
✨ <Tr t={Translations.t.general.add.title} />
|
||||
{:else}
|
||||
<Tr t={Translations.t.notes.addAComment} />
|
||||
|
@ -351,9 +351,9 @@
|
|||
<div
|
||||
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">
|
||||
<Tr t={layout.title} />
|
||||
<Tr t={theme.title} />
|
||||
</b>
|
||||
</div>
|
||||
</MapControlButton>
|
||||
|
|
|
@ -52,7 +52,7 @@ export class PngMapCreator {
|
|||
|
||||
PngMapCreator.id++
|
||||
try {
|
||||
const layout = this._state.layout
|
||||
const layout = this._state.theme
|
||||
|
||||
function setState(msg: string) {
|
||||
status?.setData(layout.id + ": " + msg)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { QueryParameters } from "./Logic/Web/QueryParameters"
|
||||
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 l = window.location
|
||||
if (layout !== "") {
|
||||
if (theme !== "") {
|
||||
if (window.location.host.startsWith("127.0.0.1")) {
|
||||
window.location.replace(
|
||||
l.protocol +
|
||||
|
@ -13,12 +13,12 @@ if (layout !== "") {
|
|||
"/theme.html" +
|
||||
l.search +
|
||||
"&layout=" +
|
||||
layout +
|
||||
theme +
|
||||
l.hash
|
||||
)
|
||||
} else {
|
||||
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 !== "") {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue