From 73f32e0ecfb818fb00698985132b3f89f9737eeb Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 11 Nov 2020 16:23:49 +0100 Subject: [PATCH] Refactored out 'layout.ts' --- AllTranslationAssets.ts | 29 +++- Customizations/AllKnownLayouts.ts | 84 ++++------- Customizations/JSON/FromJSON.ts | 26 ---- Customizations/JSON/LayoutConfig.ts | 98 +++++++++++++ Customizations/JSON/LayoutConfigJson.ts | 22 ++- Customizations/Layout.ts | 131 ------------------ InitUiElements.ts | 29 ++-- Logic/MetaTagging.ts | 7 +- Logic/Osm/ChangesetHandler.ts | 8 +- Logic/Osm/OsmConnection.ts | 4 +- Logic/PersonalLayersPanel.ts | 16 ++- Logic/PersonalLayout.ts | 26 ---- State.ts | 40 +++--- UI/MoreScreen.ts | 14 +- UI/ShareScreen.ts | 9 +- UI/UserBadge.ts | 2 +- UI/WelcomeMessage.ts | 17 ++- UI/i18n/Translation.ts | 31 +++-- UI/i18n/Translations.ts | 11 -- .../bike_monitoring_stations.json | 1 + assets/themes/buurtnatuur/buurtnatuur.json | 3 + assets/themes/cyclofix/logo.svg | 26 ++-- .../themes/drinking_water/drinking_water.json | 22 +++ assets/themes/drinking_water/logo.svg | 106 ++++++++++++++ assets/themes/fritures/fritures.json | 3 +- .../themes/personalLayout/personalLayout.json | 37 +++++ assets/themes/widths/width.json | 9 ++ assets/translations.json | 15 -- createLayouts.ts | 28 ++-- index.ts | 11 +- 30 files changed, 465 insertions(+), 400 deletions(-) create mode 100644 Customizations/JSON/LayoutConfig.ts delete mode 100644 Customizations/Layout.ts delete mode 100644 Logic/PersonalLayout.ts create mode 100644 assets/themes/drinking_water/drinking_water.json create mode 100644 assets/themes/drinking_water/logo.svg create mode 100644 assets/themes/personalLayout/personalLayout.json diff --git a/AllTranslationAssets.ts b/AllTranslationAssets.ts index 17d9bd1..1ee4360 100644 --- a/AllTranslationAssets.ts +++ b/AllTranslationAssets.ts @@ -120,10 +120,27 @@ export default class AllTranslationAssets { ph_open: new Translation( {"en":"opened","ca":"tancat","es":"abierto","nl":"open"} ), }, }, - favourite: { title: new Translation( {"en":"Personal theme","nl":"Persoonlijk thema","es":"Interficie personal","ca":"Interfície personal","gl":"Tema personalizado","de":"Persönliches Thema"} ), - description: new Translation( {"en":"Create a personal theme based on all the available layers of all themes","es":"Crea una interficie basada en todas las capas disponibles de todas las interficies","ca":"Crea una interfície basada en totes les capes disponibles de totes les interfícies","gl":"Crea un tema baseado en todas as capas dispoñíbeis de todos os temas","de":"Erstellen Sie ein persönliches Thema auf der Grundlage aller verfügbaren Ebenen aller Themen"} ), - panelIntro: new Translation( {"en":"

Your personal theme

Activate your favourite layers from all the official themes","ca":"

La teva interfície personal

Activa les teves capes favorites de totes les interfícies oficials","es":"

Tu interficie personal

Activa tus capas favoritas de todas las interficies oficiales","gl":"

O teu tema personalizado

Activa as túas capas favoritas de todos os temas oficiais","de":"

Ihr persönliches Thema

Aktivieren Sie Ihre Lieblingsebenen aus allen offiziellen Themen"} ), - loginNeeded: new Translation( {"en":"

Log in

A personal layout is only available for OpenStreetMap users","es":"

Entrar

El diseño personalizado sólo está disponible para los usuarios de OpenstreetMap","ca":"

Entrar

El disseny personalizat només està disponible pels usuaris d' OpenstreetMap","gl":"

Iniciar a sesión

O deseño personalizado só está dispoñíbel para os usuarios do OpenstreetMap","de":"

Anmelden

Ein persönliches Layout ist nur für OpenStreetMap-Benutzer verfügbar"} ), - reload: new Translation( {"en":"Reload the data","es":"Recargar datos","ca":"Recarregar dades","gl":"Recargar os datos","de":"Daten neu laden"} ), -}, + favourite: { + panelIntro: new Translation({ + "en": "

Your personal theme

Activate your favourite layers from all the official themes", + "ca": "

La teva interfície personal

Activa les teves capes favorites de totes les interfícies oficials", + "es": "

Tu interficie personal

Activa tus capas favoritas de todas las interficies oficiales", + "gl": "

O teu tema personalizado

Activa as túas capas favoritas de todos os temas oficiais", + "de": "

Ihr persönliches Thema

Aktivieren Sie Ihre Lieblingsebenen aus allen offiziellen Themen" + }), + loginNeeded: new Translation({ + "en": "

Log in

A personal layout is only available for OpenStreetMap users", + "es": "

Entrar

El diseño personalizado sólo está disponible para los usuarios de OpenstreetMap", + "ca": "

Entrar

El disseny personalizat només està disponible pels usuaris d' OpenstreetMap", + "gl": "

Iniciar a sesión

O deseño personalizado só está dispoñíbel para os usuarios do OpenstreetMap", + "de": "

Anmelden

Ein persönliches Layout ist nur für OpenStreetMap-Benutzer verfügbar" + }), + reload: new Translation({ + "en": "Reload the data", + "es": "Recargar datos", + "ca": "Recarregar dades", + "gl": "Recargar os datos", + "de": "Daten neu laden" + }), + }, }} \ No newline at end of file diff --git a/Customizations/AllKnownLayouts.ts b/Customizations/AllKnownLayouts.ts index 10796d6..e00ca6c 100644 --- a/Customizations/AllKnownLayouts.ts +++ b/Customizations/AllKnownLayouts.ts @@ -1,4 +1,3 @@ -import {Layout} from "./Layout"; import * as bookcases from "../assets/themes/bookcases/Bookcases.json"; import * as aed from "../assets/themes/aed/aed.json"; import * as toilets from "../assets/themes/toilets/toilets.json"; @@ -15,17 +14,18 @@ import * as fritures from "../assets/themes/fritures/fritures.json" import * as benches from "../assets/themes/benches/benches.json"; import * as charging_stations from "../assets/themes/charging_stations/charging_stations.json" import * as widths from "../assets/themes/widths/width.json" - -import {PersonalLayout} from "../Logic/PersonalLayout"; +import * as drinking_water from "../assets/themes/drinking_water/drinking_water.json" import LayerConfig from "./JSON/LayerConfig"; import SharedLayers from "./SharedLayers"; +import * as personal from "../assets/themes/personalLayout/personalLayout.json" +import LayoutConfig from "./JSON/LayoutConfig"; export class AllKnownLayouts { public static allLayers: Map = undefined; - private static GenerateCycloFix(): Layout { - const layout = Layout.LayoutFromJSON(cyclofix, SharedLayers.sharedLayers) + private static GenerateCycloFix(): LayoutConfig { + const layout = new LayoutConfig(cyclofix) const now = new Date(); const m = now.getMonth() + 1; const day = new Date().getDate() + 1; @@ -41,63 +41,31 @@ export class AllKnownLayouts { return layout; } - - private static GenerateWidths(): Layout { - const layout = Layout.LayoutFromJSON(widths, SharedLayers.sharedLayers); - - layout.enableUserBadge = false; - layout.enableShareScreen = false; - layout.enableMoreQuests = false; - layout.enableLayers = false; - layout.hideFromOverview = true; - layout.enableSearch = false; - layout.enableGeolocation = false; - return layout; - } - - private static GenerateBuurtNatuur(): Layout { - const layout = Layout.LayoutFromJSON(buurtnatuur, SharedLayers.sharedLayers); - layout.enableMoreQuests = false; - layout.enableShareScreen = false; - layout.hideFromOverview = true; - console.log("Buurtnatuur:",layout) - return layout; - } - - private static GenerateBikeMonitoringStations(): Layout { - const layout = Layout.LayoutFromJSON(bike_monitoring_stations, SharedLayers.sharedLayers); - layout.hideFromOverview = true; - return layout; - } - - - - public static layoutsList: Layout[] = [ - new PersonalLayout(), - - Layout.LayoutFromJSON(shops, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(bookcases, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(aed, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(toilets, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(artworks, SharedLayers.sharedLayers), + public static layoutsList: LayoutConfig[] = [ + new LayoutConfig(personal), AllKnownLayouts.GenerateCycloFix(), - Layout.LayoutFromJSON(ghostbikes, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(nature, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(cyclestreets, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(maps, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(fritures, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(benches, SharedLayers.sharedLayers), - Layout.LayoutFromJSON(charging_stations, SharedLayers.sharedLayers), - AllKnownLayouts.GenerateWidths(), - AllKnownLayouts.GenerateBuurtNatuur(), - AllKnownLayouts.GenerateBikeMonitoringStations(), - + new LayoutConfig(aed), + new LayoutConfig(bookcases), + new LayoutConfig(toilets), + new LayoutConfig(artworks), + new LayoutConfig(ghostbikes), + new LayoutConfig(shops), + new LayoutConfig(drinking_water), + new LayoutConfig(nature), + new LayoutConfig(cyclestreets), + new LayoutConfig(maps), + new LayoutConfig(fritures), + new LayoutConfig(benches), + new LayoutConfig(charging_stations), + new LayoutConfig(widths), + new LayoutConfig(buurtnatuur), + new LayoutConfig(bike_monitoring_stations), ]; - public static allSets: Map = AllKnownLayouts.AllLayouts(); + public static allSets: Map = AllKnownLayouts.AllLayouts(); - private static AllLayouts(): Map { + private static AllLayouts(): Map { this.allLayers = new Map(); for (const layout of this.layoutsList) { for (let i = 0; i < layout.layers.length; i++) { @@ -118,7 +86,7 @@ export class AllKnownLayouts { } } - const allSets: Map = new Map(); + const allSets: Map = new Map(); for (const layout of this.layoutsList) { allSets[layout.id] = layout; allSets[layout.id.toLowerCase()] = layout; diff --git a/Customizations/JSON/FromJSON.ts b/Customizations/JSON/FromJSON.ts index 9276a22..949288a 100644 --- a/Customizations/JSON/FromJSON.ts +++ b/Customizations/JSON/FromJSON.ts @@ -2,35 +2,9 @@ import {AndOrTagConfigJson} from "./TagConfigJson"; import {And, Or, RegexTag, Tag, TagsFilter} from "../../Logic/Tags"; import {Utils} from "../../Utils"; -import {Translation} from "../../UI/i18n/Translation"; export class FromJSON { - - public static Translation(json: string | any): Translation { - if (json === undefined) { - return undefined; - } - if (typeof (json) === "string") { - return new Translation({"*": json}); - } - if(json.render !== undefined){ - console.error("Using a 'render' where a translation is expected. Content is", json.render); - throw "ERROR: using a 'render' where none is expected" - } - const tr = {}; - let keyCount = 0; - for (let key in json) { - keyCount++; - tr[key] = json[key]; // I'm doing this wrong, I know - } - if(keyCount == 0){ - return undefined; - } - const transl = new Translation(tr); - return transl; - } - public static SimpleTag(json: string): Tag { const tag = Utils.SplitFirst(json, "="); return new Tag(tag[0], tag[1]); diff --git a/Customizations/JSON/LayoutConfig.ts b/Customizations/JSON/LayoutConfig.ts new file mode 100644 index 0000000..2a22ccd --- /dev/null +++ b/Customizations/JSON/LayoutConfig.ts @@ -0,0 +1,98 @@ +import {Translation} from "../../UI/i18n/Translation"; +import TagRenderingConfig from "./TagRenderingConfig"; +import LayerConfig from "./LayerConfig"; +import {LayoutConfigJson} from "./LayoutConfigJson"; +import SharedLayers from "../SharedLayers"; +import SharedTagRenderings from "../SharedTagRenderings"; + +export default class LayoutConfig { + public readonly id: string; + public readonly maintainer: string; + public readonly changesetmessage?: string; + public readonly version: string; + public readonly language: string[]; + public readonly title: Translation; + public readonly shortDescription?: Translation; + public readonly description: Translation; + public readonly descriptionTail?: Translation; + public readonly icon: string; + public readonly socialImage?: string; + public readonly startZoom: number; + public readonly startLat: number; + public readonly startLon: number; + public readonly widenFactor: number; + public readonly roamingRenderings: TagRenderingConfig[]; + public readonly defaultBackgroundId?: string; + public readonly layers: LayerConfig[]; + public readonly hideFromOverview: boolean; + public readonly enableUserBadge: boolean; + public readonly enableShareScreen: boolean; + public readonly enableMoreQuests: boolean; + public readonly enableAddNewPoints: boolean; + public readonly enableLayers: boolean; + public readonly enableSearch: boolean; + public readonly enableGeolocation: boolean; + public readonly enableBackgroundLayerSelection: boolean; + public readonly customCss?: string; + + constructor(json: LayoutConfigJson, context?:string) { + this.id = json.id; + context = (context ?? "")+"."+this.id; + this.maintainer = json.maintainer; + this.changesetmessage = json.changesetmessage; + this.version = json.version; + this.language = []; + if (typeof json.language === "string") { + this.language = [json.language]; + } else { + this.language = json.language; + } + if(json.title === undefined){ + throw "Title not defined in "+this.id; + } + if(json.description === undefined){ + throw "Description not defined in "+this.id; + } + this.title = new Translation(json.title, context+".title"); + this.description = new Translation(json.description, context+".description"); + this.shortDescription = json.shortDescription === undefined ? this.description.FirstSentence() : new Translation(json.shortDescription, context+".shortdescription"); + this.descriptionTail = json.descriptionTail === undefined ? new Translation({"*":""}, context) : new Translation(json.descriptionTail, context+".descriptionTail"); + this.icon = json.icon; + this.socialImage = json.socialImage; + this.startZoom = json.startZoom; + this.startLat = json.startLat; + this.startLon = json.startLon; + this.widenFactor = json.widenFactor ?? 0.05; + this.roamingRenderings = (json.roamingRenderings ?? []).map((tr, i) => { + if (typeof tr === "string") { + if (SharedTagRenderings.SharedTagRendering[tr] !== undefined) { + return SharedTagRenderings.SharedTagRendering[tr]; + } + } + return new TagRenderingConfig(tr, `${this.id}.roaming_renderings[${i}]`); + } + ); + this.defaultBackgroundId = json.defaultBackgroundId; + this.layers = json.layers.map((layer, i) => { + if (typeof layer === "string") + if (SharedLayers.sharedLayers[layer] !== undefined) { + return SharedLayers.sharedLayers[layer]; + } else { + throw "Unkown fixed layer " + layer; + } + return new LayerConfig(layer, `${this.id}.layers[${i}]`); + }); + this.hideFromOverview = json.hideFromOverview ?? false; + + this.enableUserBadge = json.enableUserBadge ?? true; + this.enableShareScreen = json.enableShareScreen ?? true; + this.enableMoreQuests = json.enableMoreQuests ?? true; + this.enableLayers = json.enableLayers ?? true; + this.enableSearch = json.enableSearch ?? true; + this.enableGeolocation = json.enableGeolocation ?? true; + this.enableAddNewPoints = json.enableAddNewPoints ?? true; + this.enableBackgroundLayerSelection = json.enableBackgroundLayerSelection ?? true; + this.customCss = json.customCss; + } + +} \ No newline at end of file diff --git a/Customizations/JSON/LayoutConfigJson.ts b/Customizations/JSON/LayoutConfigJson.ts index f64732e..95c14c4 100644 --- a/Customizations/JSON/LayoutConfigJson.ts +++ b/Customizations/JSON/LayoutConfigJson.ts @@ -106,9 +106,21 @@ export interface LayoutConfigJson { */ layers: (LayerConfigJson | string)[], - + /** + * The URL of a custom CSS stylesheet to modify the layout + */ + customCss?: string; + /** + * If set to true, this layout will not be shown in the overview with more themes + */ + hideFromOverview?: boolean; - - - -} \ No newline at end of file + enableUserBadge?: boolean; + enableShareScreen?: boolean; + enableMoreQuests?: boolean; + enableLayers?: boolean; + enableSearch?: boolean; + enableAddNewPoints?: boolean; + enableGeolocation?: boolean; + enableBackgroundLayerSelection?: boolean; +} diff --git a/Customizations/Layout.ts b/Customizations/Layout.ts deleted file mode 100644 index 777bbdf..0000000 --- a/Customizations/Layout.ts +++ /dev/null @@ -1,131 +0,0 @@ -import {UIElement} from "../UI/UIElement"; -import Translations from "../UI/i18n/Translations"; -import Combine from "../UI/Base/Combine"; -import State from "../State"; -import LayerConfig from "./JSON/LayerConfig"; -import {LayoutConfigJson} from "./JSON/LayoutConfigJson"; -import TagRenderingConfig from "./JSON/TagRenderingConfig"; -import {FromJSON} from "./JSON/FromJSON"; -import {Translation} from "../UI/i18n/Translation"; -import Svg from "../Svg"; -import {Img} from "../UI/Img"; - -/** - * A layout is a collection of settings of the global view (thus: welcome text, title, selection of layers). - */ -export class Layout { - - public id: string; - public icon: string = Img.AsData(Svg.bug); - public title: UIElement; - public maintainer: string; - public version: string; - public description: string | UIElement; - public changesetMessage: string; - public socialImage: string = ""; - /** - * Custom CSS link - */ - public customCss: string = undefined; - - public layers: LayerConfig[]; - public welcomeMessage: UIElement; - public gettingStartedPlzLogin: UIElement; - public welcomeBackMessage: UIElement; - public welcomeTail: UIElement; - - public supportedLanguages: string[]; - - public startzoom: number; - public startLon: number; - public startLat: number; - - public enableAdd: boolean = true; - public enableUserBadge: boolean = true; - public enableSearch: boolean = true; - public enableLayers: boolean = true; - public enableBackgroundLayers: boolean = true; - public enableMoreQuests: boolean = true; - public enableShareScreen: boolean = true; - public enableGeolocation: boolean = true; - public hideFromOverview: boolean = false; - - /** - * The BBOX of the currently visible map are widened by this factor, in order to make some panning possible. - * This number influences this - */ - public widenFactor: number = 0.07; - public defaultBackground: string = "osm"; - - public static LayoutFromJSON(json: LayoutConfigJson, sharedLayers): Layout { - const tr = FromJSON.Translation; - const layers = json.layers.map(jsonLayer => { - if(typeof jsonLayer === "string"){ - return sharedLayers[jsonLayer]; - } - return new LayerConfig(jsonLayer, "theme."+json.id); - }); - const roaming: TagRenderingConfig[] = json.roamingRenderings?.map((tr, i) => - new TagRenderingConfig(tr, `theme.${json.id}.roamingRendering[${i}]`)) ?? []; - for (const layer of layers) { - layer.tagRenderings.push(...roaming); - } - - const layout = new Layout( - json.id, - typeof (json.language) === "string" ? [json.language] : json.language, - tr(json.title ?? "Title not defined"), - layers, - json.startZoom, - json.startLat, - json.startLon, - new Combine(["

", tr(json.title), "

", tr(json.description)]), - undefined, - undefined, - tr(json.descriptionTail) - - ); - - layout.defaultBackground = json.defaultBackgroundId ?? "osm"; - layout.widenFactor = json.widenFactor ?? 0.07; - layout.icon = json.icon; - layout.maintainer = json.maintainer; - layout.version = json.version; - layout.socialImage = json.socialImage; - layout.description = tr(json.shortDescription) ?? tr(json.description)?.FirstSentence(); - layout.changesetMessage = json.changesetmessage; - return layout; - } - - constructor( - id: string, - supportedLanguages: string[], - title: Translation | string, - layers: LayerConfig[], - startzoom: number, - startLat: number, - startLon: number, - welcomeMessage: UIElement | string, - gettingStartedPlzLogin: UIElement | string = new Combine([ - Translations.t.general.getStartedLogin - .SetClass("soft") - .onClick(() => {State.state.osmConnection.AttemptLogin()}), - Translations.t.general.getStartedNewAccount - ]), - welcomeBackMessage: UIElement | string = Translations.t.general.welcomeBack, - welcomeTail: UIElement | string = "", - ) { - this.supportedLanguages = supportedLanguages; - this.title = Translations.WT(title) - this.startLon = startLon; - this.startLat = startLat; - this.startzoom = startzoom; - this.id = id; - this.layers = layers; - this.welcomeMessage = Translations.W(welcomeMessage) - this.gettingStartedPlzLogin = Translations.W(gettingStartedPlzLogin); - this.welcomeBackMessage = Translations.W(welcomeBackMessage); - this.welcomeTail = Translations.W(welcomeTail); - } -} - diff --git a/InitUiElements.ts b/InitUiElements.ts index be5220d..4b9a855 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -15,7 +15,6 @@ import {VariableUiElement} from "./UI/Base/VariableUIElement"; import {UpdateFromOverpass} from "./Logic/UpdateFromOverpass"; import {UIEventSource} from "./Logic/UIEventSource"; import {QueryParameters} from "./Logic/Web/QueryParameters"; -import {PersonalLayout} from "./Logic/PersonalLayout"; import {PersonalLayersPanel} from "./Logic/PersonalLayersPanel"; import Locale from "./UI/i18n/Locale"; import {StrayClickHandler} from "./Logic/Leaflet/StrayClickHandler"; @@ -27,15 +26,15 @@ import {UserBadge} from "./UI/UserBadge"; import {SearchAndGo} from "./UI/SearchAndGo"; import {FullScreenMessageBox} from "./UI/FullScreenMessageBoxHandler"; import {GeoLocationHandler} from "./Logic/Leaflet/GeoLocationHandler"; -import {Layout} from "./Customizations/Layout"; import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; import {Utils} from "./Utils"; import BackgroundSelector from "./UI/BackgroundSelector"; import AvailableBaseLayers from "./Logic/AvailableBaseLayers"; import {FeatureInfoBox} from "./UI/Popup/FeatureInfoBox"; -import SharedLayers from "./Customizations/SharedLayers"; import Svg from "./Svg"; import Link from "./UI/Base/Link"; +import * as personal from "./assets/themes/personalLayout/personalLayout.json" +import LayoutConfig from "./Customizations/JSON/LayoutConfig"; export class InitUiElements { @@ -74,7 +73,7 @@ export class InitUiElements { } - static InitAll(layoutToUse: Layout, layoutFromBase64: string, testing: UIEventSource, layoutName: string, + static InitAll(layoutToUse: LayoutConfig, layoutFromBase64: string, testing: UIEventSource, layoutName: string, layoutDefinition: string = "") { if (layoutToUse === undefined) { console.log("Incorrect layout") @@ -115,7 +114,7 @@ export class InitUiElements { function updateFavs() { const favs = State.state.favouriteLayers.data ?? []; - layoutToUse.layers = []; + layoutToUse.layers.splice(0, layoutToUse.layers.length); for (const fav of favs) { const layer = AllKnownLayouts.allLayers[fav]; if (!!layer) { @@ -140,8 +139,7 @@ export class InitUiElements { } - if (layoutToUse === AllKnownLayouts.allSets[PersonalLayout.NAME]) { - + if (layoutToUse.id === personal.id) { State.state.favouriteLayers.addCallback(updateFavs); State.state.installedThemes.addCallback(updateFavs); } @@ -208,15 +206,8 @@ export class InitUiElements { .SetStyle(`position:relative;display:block;border: solid 2px #0005;cursor: pointer; z-index: 999; /*Just below leaflets zoom*/background-color: white;border-radius: 5px;width: 43px;height: 43px;`) .AttachTo("geolocate-button"); State.state.locationControl.ping(); - - } - - public static FromBase64(layoutFromBase64: string): Layout { - return Layout.LayoutFromJSON(JSON.parse(atob(layoutFromBase64)), SharedLayers.sharedLayers); - } - - + static LoadLayoutFromHash(userLayoutParam: UIEventSource) { try { let hash = location.hash.substr(1); @@ -236,7 +227,7 @@ export class InitUiElements { hashFromLocalStorage.setData(hash); dedicatedHashFromLocalStorage.setData(hash); } - const layoutToUse = InitUiElements.FromBase64(hash); + const layoutToUse = new LayoutConfig(JSON.parse(atob(hash))); userLayoutParam.setData(layoutToUse.id); return layoutToUse; } catch (e) { @@ -264,7 +255,7 @@ export class InitUiElements { const layoutToUse = State.state.layoutToUse.data; let welcome: UIElement = new WelcomeMessage(); - if (layoutToUse.id === PersonalLayout.NAME) { + if (layoutToUse.id === personal.id) { welcome = new PersonalLayersPanel(); } @@ -351,7 +342,7 @@ export class InitUiElements { let layerControlPanel: UIElement = undefined; - if (State.state.layoutToUse.data.enableBackgroundLayers) { + if (State.state.layoutToUse.data.enableBackgroundLayerSelection) { layerControlPanel = new BackgroundSelector(); layerControlPanel.SetStyle("margin:1em"); layerControlPanel.onClick(() => { }); @@ -451,7 +442,7 @@ export class InitUiElements { State.state.layerUpdater = new UpdateFromOverpass(State.state); State.state.availableBackgroundLayers = new AvailableBaseLayers(State.state).availableEditorLayers; - const queryParam = QueryParameters.GetQueryParameter("background", State.state.layoutToUse.data.defaultBackground); + const queryParam = QueryParameters.GetQueryParameter("background", State.state.layoutToUse.data.defaultBackgroundId); queryParam.addCallbackAndRun((selectedId: string) => { const available = State.state.availableBackgroundLayers.data; diff --git a/Logic/MetaTagging.ts b/Logic/MetaTagging.ts index 3aa3280..e4acd42 100644 --- a/Logic/MetaTagging.ts +++ b/Logic/MetaTagging.ts @@ -246,7 +246,12 @@ export default class MetaTagging { static addMetatags(features: any[]) { for (const metatag of MetaTagging.metatags) { - metatag.addMetaTags(features); + try { + metatag.addMetaTags(features); + } catch (e) { + console.error("Could not calculate metatag ", metatag.keys.join(","), ":", e) + + } } } diff --git a/Logic/Osm/ChangesetHandler.ts b/Logic/Osm/ChangesetHandler.ts index a7f777d..a432bc0 100644 --- a/Logic/Osm/ChangesetHandler.ts +++ b/Logic/Osm/ChangesetHandler.ts @@ -1,9 +1,9 @@ import {OsmConnection, UserDetails} from "./OsmConnection"; import {UIEventSource} from "../UIEventSource"; import {ElementStorage} from "../ElementStorage"; -import {Layout} from "../../Customizations/Layout"; import State from "../../State"; import Locale from "../../UI/i18n/Locale"; +import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; export class ChangesetHandler { @@ -26,7 +26,7 @@ export class ChangesetHandler { public UploadChangeset( - layout: Layout, + layout: LayoutConfig, allElements: ElementStorage, generateChangeXML: (csid: string) => string, continuation: () => void) { @@ -85,10 +85,10 @@ export class ChangesetHandler { private OpenChangeset( - layout : Layout, + layout : LayoutConfig, continuation: (changesetId: string) => void) { - const commentExtra = layout.changesetMessage !== undefined ? " - " + layout.changesetMessage : ""; + const commentExtra = layout.changesetmessage !== undefined ? " - " + layout.changesetmessage : ""; let surveySource = ""; if (State.state.currentGPSLocation.data !== undefined) { diff --git a/Logic/Osm/OsmConnection.ts b/Logic/Osm/OsmConnection.ts index d98bfff..047198e 100644 --- a/Logic/Osm/OsmConnection.ts +++ b/Logic/Osm/OsmConnection.ts @@ -3,10 +3,10 @@ import osmAuth from "osm-auth"; import {UIEventSource} from "../UIEventSource"; import {OsmPreferences} from "./OsmPreferences"; import {ChangesetHandler} from "./ChangesetHandler"; -import {Layout} from "../../Customizations/Layout"; import {ElementStorage} from "../ElementStorage"; import {Img} from "../../UI/Img"; import Svg from "../../Svg"; +import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; export class UserDetails { @@ -97,7 +97,7 @@ export class OsmConnection { public UploadChangeset( - layout: Layout, + layout: LayoutConfig, allElements: ElementStorage, generateChangeXML: (csid: string) => string, continuation: () => void = () => {}) { diff --git a/Logic/PersonalLayersPanel.ts b/Logic/PersonalLayersPanel.ts index 8e7b4f3..bbb0fb1 100644 --- a/Logic/PersonalLayersPanel.ts +++ b/Logic/PersonalLayersPanel.ts @@ -5,12 +5,12 @@ import {UIEventSource} from "./UIEventSource"; import {AllKnownLayouts} from "../Customizations/AllKnownLayouts"; import Combine from "../UI/Base/Combine"; import CheckBox from "../UI/Input/CheckBox"; -import {PersonalLayout} from "./PersonalLayout"; -import {Layout} from "../Customizations/Layout"; +import * as personal from "../assets/themes/personalLayout/personalLayout.json"; import {SubtleButton} from "../UI/Base/SubtleButton"; import {FixedUiElement} from "../UI/Base/FixedUiElement"; import {Img} from "../UI/Img"; import Svg from "../Svg"; +import LayoutConfig from "../Customizations/JSON/LayoutConfig"; export class PersonalLayersPanel extends UIElement { private checkboxes: UIElement[] = []; @@ -22,19 +22,19 @@ export class PersonalLayersPanel extends UIElement { this.UpdateView([]); const self = this; State.state.installedThemes.addCallback(extraThemes => { - self.UpdateView(extraThemes.map(layout => layout.layout)); + self.UpdateView(extraThemes.map(layout => layout.layout.layoutConfig)); self.Update(); }) } - private UpdateView(extraThemes: Layout[]) { + private UpdateView(extraThemes: LayoutConfig[]) { this.checkboxes = []; const favs = State.state.favouriteLayers.data ?? []; const controls = new Map>(); const allLayouts = AllKnownLayouts.layoutsList.concat(extraThemes); for (const layout of allLayouts) { - if (layout.id === PersonalLayout.NAME) { + if (layout.id === personal.id) { continue; } @@ -44,11 +44,15 @@ export class PersonalLayersPanel extends UIElement { "", layout.title, "
", - layout.description ?? "" + layout.shortDescription ?? "" ]).SetStyle("background: #eee; display: block; padding: 0.5em; border-radius:0.5em; overflow:auto;") this.checkboxes.push(header); for (const layer of layout.layers) { + if(layer === undefined){ + console.warn("Undefined layer for ",layout.id) + continue; + } if (typeof layer === "string") { continue; } diff --git a/Logic/PersonalLayout.ts b/Logic/PersonalLayout.ts deleted file mode 100644 index 2ae11ae..0000000 --- a/Logic/PersonalLayout.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {Layout} from "../Customizations/Layout"; -import Translations from "../UI/i18n/Translations"; -import {Img} from "../UI/Img"; -import Svg from "../Svg"; - -export class PersonalLayout extends Layout { - - public static NAME: string = "personal"; - - constructor() { - super( - PersonalLayout.NAME, - ["en"], - Translations.t.favourite.title, - [], - 12, - 0, - 0, - Translations.t.favourite.description, - ); - this.maintainer = "MapComplete" - this.description = "The personal theme allows to select one or more layers from all the layouts, creating a truly personal editor" - this.icon = Img.AsData(Svg.add) - } - -} \ No newline at end of file diff --git a/State.ts b/State.ts index f7f923e..19e041a 100644 --- a/State.ts +++ b/State.ts @@ -1,5 +1,4 @@ import {UIElement} from "./UI/UIElement"; -import {Layout} from "./Customizations/Layout"; import {Utils} from "./Utils"; import {ElementStorage} from "./Logic/ElementStorage"; import {Changes} from "./Logic/Osm/Changes"; @@ -12,6 +11,7 @@ import {UIEventSource} from "./Logic/UIEventSource"; import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; import {QueryParameters} from "./Logic/Web/QueryParameters"; import {BaseLayer} from "./Logic/BaseLayer"; +import LayoutConfig from "./Customizations/JSON/LayoutConfig"; /** * Contains the global state: a bunch of UI-event sources @@ -38,9 +38,9 @@ export default class State { minZoomLevelToAddNewPoints: (Utils.isRetina() ? 18 : 19) }; - public static runningFromConsole: boolean = false; + public static runningFromConsole: boolean = false; - public readonly layoutToUse = new UIEventSource(undefined); + public readonly layoutToUse = new UIEventSource(undefined); /** The mapping from id -> UIEventSource @@ -113,7 +113,7 @@ export default class State { accuracy: number }> = new UIEventSource<{ latlng: {lat:number, lng:number}, accuracy: number }>(undefined); public layoutDefinition: string; - public installedThemes: UIEventSource<{ layout: Layout; definition: string }[]>; + public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; public layerControlIsOpened: UIEventSource = QueryParameters.GetQueryParameter("layer-control-toggle", "false") .map((str) => str !== "false", [], b => "" + b) @@ -122,7 +122,7 @@ export default class State { str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n ); - constructor(layoutToUse: Layout) { + constructor(layoutToUse: LayoutConfig) { const self = this; this.layoutToUse.setData(layoutToUse); @@ -138,7 +138,7 @@ export default class State { }) } this.zoom = asFloat( - QueryParameters.GetQueryParameter("z", "" + layoutToUse.startzoom) + QueryParameters.GetQueryParameter("z", "" + layoutToUse.startZoom) .syncWith(LocalStorageSource.Get("zoom"))); this.lat = asFloat(QueryParameters.GetQueryParameter("lat", "" + layoutToUse.startLat) .syncWith(LocalStorageSource.Get("lat"))); @@ -158,14 +158,14 @@ export default class State { this.layoutToUse.addCallback(layoutToUse => { const lcd = self.locationControl.data; - lcd.zoom = lcd.zoom ?? layoutToUse?.startzoom; + lcd.zoom = lcd.zoom ?? layoutToUse?.startZoom; lcd.lat = lcd.lat ?? layoutToUse?.startLat; lcd.lon = lcd.lon ?? layoutToUse?.startLon; self.locationControl.ping(); }); - function featSw(key: string, deflt: (layout: Layout) => boolean): UIEventSource { + function featSw(key: string, deflt: (layout: LayoutConfig) => boolean): UIEventSource { const queryParameterSource = QueryParameters.GetQueryParameter(key, undefined); // I'm so sorry about someone trying to decipher this @@ -182,7 +182,7 @@ export default class State { this.featureSwitchUserbadge = featSw("fs-userbadge", (layoutToUse) => layoutToUse?.enableUserBadge ?? true); this.featureSwitchSearch = featSw("fs-search", (layoutToUse) => layoutToUse?.enableSearch ?? true); this.featureSwitchLayers = featSw("fs-layers", (layoutToUse) => layoutToUse?.enableLayers ?? true); - this.featureSwitchAddNew = featSw("fs-add-new", (layoutToUse) => layoutToUse?.enableAdd ?? true); + this.featureSwitchAddNew = featSw("fs-add-new", (layoutToUse) => layoutToUse?.enableAddNewPoints ?? true); this.featureSwitchWelcomeMessage = featSw("fs-welcome-message", () => true); this.featureSwitchIframe = featSw("fs-iframe", () => false); this.featureSwitchMoreQuests = featSw("fs-more-quests", (layoutToUse) => layoutToUse?.enableMoreQuests ?? true); @@ -198,8 +198,8 @@ export default class State { ); - this.installedThemes = this.osmConnection.preferencesHandler.preferences.map<{ layout: Layout, definition: string }[]>(allPreferences => { - const installedThemes: { layout: Layout, definition: string }[] = []; + this.installedThemes = this.osmConnection.preferencesHandler.preferences.map<{ layout: LayoutConfig, definition: string }[]>(allPreferences => { + const installedThemes: { layout: LayoutConfig, definition: string }[] = []; if (allPreferences === undefined) { return installedThemes; } @@ -208,18 +208,13 @@ export default class State { const themename = allPreferencesKey.match(/^mapcomplete-installed-theme-(.*)-combined-length$/); if (themename && themename[1] !== "") { const customLayout = self.osmConnection.GetLongPreference("installed-theme-" + themename[1]); - if(customLayout.data === undefined){ + if (customLayout.data === undefined) { console.log("No data defined for ", themename[1]); continue; } try { - const layout = State.FromBase64(customLayout.data); - if(layout.id === undefined){ - // This is an old style theme - // We remove it - customLayout.setData(undefined); - continue; - } + const layout = new LayoutConfig( + JSON.parse(btoa(customLayout.data))); installedThemes.push({ layout: layout, definition: customLayout.data @@ -257,10 +252,10 @@ export default class State { if (layoutToUse === undefined) { return; } - if (this.layoutToUse.data.supportedLanguages.indexOf(currentLanguage) < 0) { - console.log("Resetting language to", layoutToUse.supportedLanguages[0], "as", currentLanguage, " is unsupported") + if (this.layoutToUse.data.language.indexOf(currentLanguage) < 0) { + console.log("Resetting language to", layoutToUse.language[0], "as", currentLanguage, " is unsupported") // The current language is not supported -> switch to a supported one - Locale.language.setData(layoutToUse.supportedLanguages[0]); + Locale.language.setData(layoutToUse.language[0]); } }).ping() @@ -288,5 +283,4 @@ export default class State { } - public static FromBase64 : (data: string) => Layout = undefined; } diff --git a/UI/MoreScreen.ts b/UI/MoreScreen.ts index fb5dab3..a3f58dc 100644 --- a/UI/MoreScreen.ts +++ b/UI/MoreScreen.ts @@ -6,11 +6,9 @@ import Combine from "./Base/Combine"; import {SubtleButton} from "./Base/SubtleButton"; import State from "../State"; import {VariableUiElement} from "./Base/VariableUIElement"; -import {PersonalLayout} from "../Logic/PersonalLayout"; -import {Layout} from "../Customizations/Layout"; import Svg from "../Svg"; -import {Img} from "./Img"; - +import LayoutConfig from "../Customizations/JSON/LayoutConfig"; +import * as personal from "../assets/themes/personalLayout/personalLayout.json" export class MoreScreen extends UIElement { @@ -21,7 +19,7 @@ export class MoreScreen extends UIElement { this.ListenTo(State.state.installedThemes); } - private createLinkButton(layout: Layout, customThemeDefinition: string = undefined) { + private createLinkButton(layout: LayoutConfig, customThemeDefinition: string = undefined) { if (layout === undefined) { return undefined; } @@ -53,7 +51,7 @@ export class MoreScreen extends UIElement { } - let description = Translations.W(layout.description); + let description = Translations.W(layout.shortDescription); if (description !== undefined) { description = new Combine(["
", description]); } @@ -88,8 +86,8 @@ export class MoreScreen extends UIElement { for (const k in AllKnownLayouts.allSets) { - const layout : Layout = AllKnownLayouts.allSets[k]; - if (k === PersonalLayout.NAME) { + const layout : LayoutConfig = AllKnownLayouts.allSets[k]; + if (k === personal.id) { if (State.state.osmConnection.userDetails.data.csCount < State.userJourney.personalLayoutUnlock) { continue; } diff --git a/UI/ShareScreen.ts b/UI/ShareScreen.ts index b6d00ce..a682c6c 100644 --- a/UI/ShareScreen.ts +++ b/UI/ShareScreen.ts @@ -5,16 +5,15 @@ import Combine from "./Base/Combine"; import {VariableUiElement} from "./Base/VariableUIElement"; import CheckBox from "./Input/CheckBox"; import {VerticalCombine} from "./Base/VerticalCombine"; -import {Img} from "./Img"; import State from "../State"; import {Basemap} from "../Logic/Leaflet/Basemap"; import {FilteredLayer} from "../Logic/FilteredLayer"; import {Utils} from "../Utils"; import {UIEventSource} from "../Logic/UIEventSource"; import {SubtleButton} from "./Base/SubtleButton"; -import {Layout} from "../Customizations/Layout"; import Svg from "../Svg"; import {Translation} from "./i18n/Translation"; +import LayoutConfig from "../Customizations/JSON/LayoutConfig"; export class ShareScreen extends UIElement { private readonly _options: UIElement; @@ -24,7 +23,7 @@ export class ShareScreen extends UIElement { private readonly _linkStatus: UIEventSource; private readonly _editLayout: UIElement; - constructor(layout: Layout = undefined, layoutDefinition: string = undefined) { + constructor(layout: LayoutConfig = undefined, layoutDefinition: string = undefined) { super(undefined) layout = layout ?? State.state?.layoutToUse?.data; layoutDefinition = layoutDefinition ?? State.state?.layoutDefinition; @@ -164,12 +163,12 @@ export class ShareScreen extends UIElement { }, optionParts); - this.iframe = url.map(url => `<iframe src="${url}" width="100%" height="100%" title="${layout.title?.InnerRender()??"MapComplete"} with MapComplete"></iframe>`); + this.iframe = url.map(url => `<iframe src="${url}" width="100%" height="100%" title="${layout?.title?.txt ?? "MapComplete"} with MapComplete"></iframe>`); this._iframeCode = new VariableUiElement( url.map((url) => { return ` - <iframe src="${url}" width="100%" height="100%" title="${layout.title?.InnerRender() ?? "MapComplete"} with MapComplete"></iframe> + <iframe src="${url}" width="100%" height="100%" title="${layout.title?.txt ?? "MapComplete"} with MapComplete"></iframe> ` }) ); diff --git a/UI/UserBadge.ts b/UI/UserBadge.ts index 6338e5a..49e8acf 100644 --- a/UI/UserBadge.ts +++ b/UI/UserBadge.ts @@ -26,7 +26,7 @@ export class UserBadge extends UIElement { constructor() { super(State.state.osmConnection.userDetails); this._userDetails = State.state.osmConnection.userDetails; - this._languagePicker = (LanguagePicker.CreateLanguagePicker(State.state.layoutToUse.data.supportedLanguages) ?? new FixedUiElement("")) + this._languagePicker = (LanguagePicker.CreateLanguagePicker(State.state.layoutToUse.data.language) ?? new FixedUiElement("")) .SetStyle("display:inline-block;width:min-content;"); this._loginButton = Translations.t.general.loginWithOpenStreetMap diff --git a/UI/WelcomeMessage.ts b/UI/WelcomeMessage.ts index 7079036..8fe2c00 100644 --- a/UI/WelcomeMessage.ts +++ b/UI/WelcomeMessage.ts @@ -18,17 +18,24 @@ export class WelcomeMessage extends UIElement { constructor() { super(State.state.osmConnection.userDetails); this.ListenTo(Locale.language); - this.languagePicker = LanguagePicker.CreateLanguagePicker(State.state.layoutToUse.data.supportedLanguages, Translations.t.general.pickLanguage); + this.languagePicker = LanguagePicker.CreateLanguagePicker(State.state.layoutToUse.data.language, Translations.t.general.pickLanguage); const layout = State.state.layoutToUse.data; - this.description =Translations.W(layout.welcomeMessage); + this.description = new Combine([ + "

", layout.title, "

", + layout.description + + ]) + layout.descriptionTail + + this.plzLogIn = - Translations.W(layout.gettingStartedPlzLogin) + Translations.t.general.loginWithOpenStreetMap .onClick(() => { State.state.osmConnection.AttemptLogin() }); - this.welcomeBack = Translations.W(layout.welcomeBackMessage); - this.tail = Translations.W(layout.welcomeTail); + this.welcomeBack = Translations.t.general.welcomeBack; + this.tail = layout.descriptionTail; } InnerRender(): string { diff --git a/UI/i18n/Translation.ts b/UI/i18n/Translation.ts index b84fc40..4d05a06 100644 --- a/UI/i18n/Translation.ts +++ b/UI/i18n/Translation.ts @@ -7,6 +7,24 @@ export class Translation extends UIElement { private static forcedLanguage = undefined; + public readonly translations: object + + constructor(translations: object, context?: string) { + super(Locale.language) + if(translations === undefined){ + throw `Translation without content (${context})` + } + let count = 0; + for (const translationsKey in translations) { + count++; + } + this.translations = translations; + if(count === 0){ + throw `No translations given in the object (${context})` + } + } + + public Subs(text: any): Translation { const newTranslations = {}; for (const lang in this.translations) { @@ -56,7 +74,7 @@ export class Translation extends UIElement { return this.translations[i]; // Return a random language } console.error("Missing language ", Locale.language.data, "for", this.translations) - return undefined; + return ""; } @@ -64,17 +82,6 @@ export class Translation extends UIElement { return this.txt } - public readonly translations: object - - constructor(translations: object) { - super(Locale.language) - let count = 0; - for (const translationsKey in translations) { - count++; - } - this.translations = translations - } - public replace(a: string, b: string) { if (a.startsWith("{") && a.endsWith("}")) { a = a.substr(1, a.length - 2); diff --git a/UI/i18n/Translations.ts b/UI/i18n/Translations.ts index 3adc92f..01b0687 100644 --- a/UI/i18n/Translations.ts +++ b/UI/i18n/Translations.ts @@ -10,17 +10,6 @@ export default class Translations { } static t = AllTranslationAssets.t; - - private static isTranslation(tr: any): boolean { - for (const key in tr) { - if (typeof tr[key] !== "string") { - return false; - } - } - return true; - } - - public static W(s: string | UIElement): UIElement { if (typeof (s) === "string") { return new FixedUiElement(s); diff --git a/assets/themes/bike_monitoring_station/bike_monitoring_stations.json b/assets/themes/bike_monitoring_station/bike_monitoring_stations.json index 0d6be70..b077b92 100644 --- a/assets/themes/bike_monitoring_station/bike_monitoring_stations.json +++ b/assets/themes/bike_monitoring_station/bike_monitoring_stations.json @@ -12,6 +12,7 @@ "language": [ "en" ], + "hideFromOverview": true, "maintainer": "", "icon": "./assets/layers/bike_monitoring_station/monitoring_station.svg", "version": "0", diff --git a/assets/themes/buurtnatuur/buurtnatuur.json b/assets/themes/buurtnatuur/buurtnatuur.json index 4a9d2db..84b24bc 100644 --- a/assets/themes/buurtnatuur/buurtnatuur.json +++ b/assets/themes/buurtnatuur/buurtnatuur.json @@ -7,6 +7,9 @@ "shortDescription": { "nl": "Met deze tool kan je natuur in je buurt in kaart brengen en meer informatie geven over je favoriete plekje" }, + "hideFromOverview": true, + "enableShareScreen": false, + "enableMoreQuests": false, "description": { "nl": "
Natuur maakt gelukkig. Aan de hand van deze website willen we de natuur dicht bij ons beter inventariseren. Met als doel meer mensen te laten genieten van toegankelijke natuur én te strijden voor meer natuur in onze buurten. \n
  • In welke natuurgebieden kan jij terecht? Hoe toegankelijk zijn ze?
  • In welke bossen kan een gezin in jouw gemeente opnieuw op adem komen?
  • Op welke onbekende plekjes is het zalig spelen?

Samen kleuren we heel Vlaanderen en Brussel groen.

Blijf op de hoogte van de resultaten van buurtnatuur.be: meld je aan voor e-mailupdates." }, diff --git a/assets/themes/cyclofix/logo.svg b/assets/themes/cyclofix/logo.svg index 059b16e..23325be 100644 --- a/assets/themes/cyclofix/logo.svg +++ b/assets/themes/cyclofix/logo.svg @@ -7,9 +7,9 @@ xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="123" - height="123" - viewBox="0 0 123 123" + width="98" + height="98" + viewBox="0 0 98 98" version="1.1" id="svg42" sodipodi:docname="logo.svg" @@ -36,17 +36,17 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="1680" - inkscape:window-height="1013" + inkscape:window-width="1920" + inkscape:window-height="1001" id="namedview44" showgrid="false" inkscape:zoom="4" - inkscape:cx="51.676089" - inkscape:cy="85.90359" + inkscape:cx="-2.2900136" + inkscape:cy="62.988337" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" - inkscape:current-layer="layer1" /> + inkscape:current-layer="layer4" /> - + transform="translate(-12.466103,-2.0847473)"> + style="display:inline" + transform="translate(-12.466103,-2.0847473)"> + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/fritures/fritures.json b/assets/themes/fritures/fritures.json index 01b27f1..c46a207 100644 --- a/assets/themes/fritures/fritures.json +++ b/assets/themes/fritures/fritures.json @@ -251,6 +251,5 @@ "wayHandling": 1 } ], - "roamingRenderings": [], - "shortDescription": {} + "roamingRenderings": [] } \ No newline at end of file diff --git a/assets/themes/personalLayout/personalLayout.json b/assets/themes/personalLayout/personalLayout.json new file mode 100644 index 0000000..f4b257e --- /dev/null +++ b/assets/themes/personalLayout/personalLayout.json @@ -0,0 +1,37 @@ +{ + "id": "personal", + "title": { + "en": "Personal theme", + "nl": "Persoonlijk thema", + "es": "Interficie personal", + "ca": "Interfície personal", + "gl": "Tema personalizado", + "de": "Persönliches Thema" + }, + "description": { + "en": "Create a personal theme based on all the available layers of all themes", + "es": "Crea una interficie basada en todas las capas disponibles de todas las interficies", + "ca": "Crea una interfície basada en totes les capes disponibles de totes les interfícies", + "gl": "Crea un tema baseado en todas as capas dispoñíbeis de todos os temas", + "de": "Erstellen Sie ein persönliches Thema auf der Grundlage aller verfügbaren Ebenen aller Themen" + }, + "language": [ + "en", + "nl", + "es", + "ca", + "gl", + "de" + ], + "maintainer": "MapComplete", + "icon": "./assets/svg/addSmall.svg", + "version": "0", + "startLat": 0, + "startLon": 0, + "startZoom": 16, + "widenFactor": 0.05, + "layers": [ + "drinking_water" + ], + "roamingRenderings": [] +} \ No newline at end of file diff --git a/assets/themes/widths/width.json b/assets/themes/widths/width.json index 6fa595f..a74278f 100644 --- a/assets/themes/widths/width.json +++ b/assets/themes/widths/width.json @@ -12,6 +12,15 @@ "language": [ "nl" ], + "hideFromOverview": true, + + "enableUserBadge": false, + "enableShareScreen":false, + "enableMoreQuests": false, + "enableLayers":false, + "enableSearch": false, + "enableGeolocation":false, + "maintainer": "", "icon": "./assets/themes/widths/icon.svg", "version": "0", diff --git a/assets/translations.json b/assets/translations.json index fc59a0f..ed34169 100644 --- a/assets/translations.json +++ b/assets/translations.json @@ -886,21 +886,6 @@ } }, "favourite": { - "title": { - "en": "Personal theme", - "nl": "Persoonlijk thema", - "es": "Interficie personal", - "ca": "Interfície personal", - "gl": "Tema personalizado", - "de": "Persönliches Thema" - }, - "description": { - "en": "Create a personal theme based on all the available layers of all themes", - "es": "Crea una interficie basada en todas las capas disponibles de todas las interficies", - "ca": "Crea una interfície basada en totes les capes disponibles de totes les interfícies", - "gl": "Crea un tema baseado en todas as capas dispoñíbeis de todos os temas", - "de": "Erstellen Sie ein persönliches Thema auf der Grundlage aller verfügbaren Ebenen aller Themen" - }, "panelIntro": { "en": "

Your personal theme

Activate your favourite layers from all the official themes", "ca": "

La teva interfície personal

Activa les teves capes favorites de totes les interfícies oficials", diff --git a/createLayouts.ts b/createLayouts.ts index d1817b1..f5b5a3e 100644 --- a/createLayouts.ts +++ b/createLayouts.ts @@ -1,22 +1,22 @@ import {Img} from "./UI/Img" - -Img.runningFromConsole = true; import {UIElement} from "./UI/UIElement"; -// We HAVE to mark this while importing -UIElement.runningFromConsole = true; import {AllKnownLayouts} from "./Customizations/AllKnownLayouts"; -import {Layout} from "./Customizations/Layout"; import {readFileSync, writeFile, writeFileSync} from "fs"; import Locale from "./UI/i18n/Locale"; import svg2img from 'promise-svg2img'; import Translations from "./UI/i18n/Translations"; import {Translation} from "./UI/i18n/Translation"; +import LayoutConfig from "./Customizations/JSON/LayoutConfig"; + +Img.runningFromConsole = true; +// We HAVE to mark this while importing +UIElement.runningFromConsole = true; function enc(str: string): string { return encodeURIComponent(str.toLowerCase()); } -function validate(layout: Layout) { +function validate(layout: LayoutConfig) { const translations: Translation[] = []; const queue: any[] = [layout] @@ -38,7 +38,7 @@ function validate(layout: Layout) { const missing = {} const present = {} - for (const ln of layout.supportedLanguages) { + for (const ln of layout.language) { missing[ln] = 0; present[ln] = 0; for (const translation of translations) { @@ -58,7 +58,7 @@ function validate(layout: Layout) { let message = `Translation completenes for theme ${layout.id}` let isComplete = true; - for (const ln of layout.supportedLanguages) { + for (const ln of layout.language) { const amiss = missing[ln]; const ok = present[ln]; const total = amiss + ok; @@ -75,11 +75,11 @@ function validate(layout: Layout) { } -function generateWikiEntry(layout: Layout){ +function generateWikiEntry(layout: LayoutConfig){ if(layout.hideFromOverview){ return ""; } - const languages = layout.supportedLanguages.map(ln => `{{#language:${ln}|en}}`).join(", ") + const languages = layout.language.map(ln => `{{#language:${ln}|en}}`).join(", ") let auth = "Yes"; if(layout.maintainer !== "" && layout.maintainer !== "MapComplete"){ auth=`Yes, by ${layout.maintainer};` @@ -97,7 +97,7 @@ function generateWikiEntry(layout: Layout){ const alreadyWritten = [] -function createIcon(iconPath: string, size: number, layout: Layout) { +function createIcon(iconPath: string, size: number, layout: LayoutConfig) { let name = iconPath.split(".").slice(0, -1).join("."); if (name.startsWith("./")) { name = name.substr(2) @@ -138,7 +138,7 @@ function createIcon(iconPath: string, size: number, layout: Layout) { return newname; } -function createManifest(layout: Layout, relativePath: string) { +function createManifest(layout: LayoutConfig, relativePath: string) { const name = layout.id; const icons = []; @@ -191,9 +191,9 @@ function createManifest(layout: Layout, relativePath: string) { } const template = readFileSync("index.html", "utf8"); -function createLandingPage(layout: Layout) { +function createLandingPage(layout: LayoutConfig) { - Locale.language.setData(layout.supportedLanguages[0]); + Locale.language.setData(layout.language[0]); const ogTitle = Translations.W(layout.title)?.InnerRender(); const ogDescr = Translations.W(layout.description ?? "Easily add and edit geodata with OpenStreetMap")?.InnerRender(); diff --git a/index.ts b/index.ts index bc242490..712f570 100644 --- a/index.ts +++ b/index.ts @@ -1,11 +1,11 @@ import {AllKnownLayouts} from "./Customizations/AllKnownLayouts"; -import {Layout} from "./Customizations/Layout"; import {FixedUiElement} from "./UI/Base/FixedUiElement"; import {InitUiElements} from "./InitUiElements"; import {QueryParameters} from "./Logic/Web/QueryParameters"; import {UIEventSource} from "./Logic/UIEventSource"; import * as $ from "jquery"; import SharedLayers from "./Customizations/SharedLayers"; +import LayoutConfig from "./Customizations/JSON/LayoutConfig"; let defaultLayout = "bookcases" // --------------------- Special actions based on the parameters ----------------- @@ -57,7 +57,7 @@ if (path !== "index.html" && path !== "") { // Run over all questsets. If a part of the URL matches a searched-for part in the layout, it'll take that as the default for (const k in AllKnownLayouts.allSets) { - const layout = AllKnownLayouts.allSets[k]; + const layout : LayoutConfig= AllKnownLayouts.allSets[k]; const possibleParts = (layout.locationContains ?? []); for (const locationMatch of possibleParts) { if (locationMatch === "") { @@ -71,7 +71,7 @@ for (const k in AllKnownLayouts.allSets) { defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout).data; -let layoutToUse: Layout = AllKnownLayouts.allSets[defaultLayout.toLowerCase()] ?? AllKnownLayouts["all"]; +let layoutToUse: LayoutConfig = AllKnownLayouts.allSets[defaultLayout.toLowerCase()] ?? AllKnownLayouts["all"]; const userLayoutParam = QueryParameters.GetQueryParameter("userlayout", "false"); @@ -94,8 +94,9 @@ if (layoutFromBase64.startsWith("wiki:")) { .firstChild.textContent; try { console.log("DOWNLOADED:",layoutJson); - const layout = Layout.LayoutFromJSON(JSON.parse(layoutJson), SharedLayers.sharedLayers); - layout.id = layoutFromBase64; + const parsed = JSON.parse(layoutJson); + parsed["id"] = layoutFromBase64 + const layout =new LayoutConfig(parsed); InitUiElements.InitAll(layout, layoutFromBase64, testing, layoutFromBase64, btoa(layoutJson)); } catch (e) { new FixedUiElement(`${themeName} is invalid:
${e}`)