diff --git a/AllTranslationAssets.ts b/AllTranslationAssets.ts index f4ca2c3..7fff07c 100644 --- a/AllTranslationAssets.ts +++ b/AllTranslationAssets.ts @@ -22,7 +22,8 @@ export default class AllTranslationAssets { ready: new Translation( {"en":"Done!","ca":"Fet.","es":"Hecho.","nl":"Klaar!","fr":"Finis!","gl":"Feito!","de":"Erledigt!"} ), retrying: new Translation( {"en":"Loading data failed. Trying again... ({count})","ca":"La càrrega de dades ha fallat.Tornant-ho a intentar... ({count})","es":"La carga de datos ha fallado.Volviéndolo a probar... ({count})","gl":"A carga dos datos fallou. Tentándoo de novo... ({count})","fr":"Le chargement a échoué. Essayer à nouveau... ({count})","de":"Laden von Daten fehlgeschlagen. Erneuter Versuch... ({count})"} ), }, - general: { loginWithOpenStreetMap: new Translation( {"en":"Login with OpenStreetMap","ca":"Entra a OpenStreetMap","es":"Entra en OpenStreetMap","nl":"Aanmelden met OpenStreetMap","fr":"Se connecter avec OpenStreeMap","gl":"Inicia a sesión no OpenStreetMap","de":"Anmeldung mit OpenStreetMap"} ), + general: { index: new Translation( {"#":"This text is shown above the theme buttons when no theme is loaded","en":"

Welcome to MapComplete

MapComplete is an OpenStreetMap-viewer and editor, which shows you information about a specific theme.

Pick a theme below to get started.","nl":"

Welkom bij MapComplete

MapComplete is een OpenStreetMap applicatie waar informatie over een specifiek thema bekeken en aangepast kan worden.

Kies hieronder een thema om te beginnen."} ), + loginWithOpenStreetMap: new Translation( {"en":"Login with OpenStreetMap","ca":"Entra a OpenStreetMap","es":"Entra en OpenStreetMap","nl":"Aanmelden met OpenStreetMap","fr":"Se connecter avec OpenStreeMap","gl":"Inicia a sesión no OpenStreetMap","de":"Anmeldung mit OpenStreetMap"} ), welcomeBack: new Translation( {"en":"You are logged in, welcome back!","ca":"Has entrat, benvingut.","es":"Has entrado, bienvenido.","nl":"Je bent aangemeld. Welkom terug!","fr":"Vous êtes connecté. Bienvenue!","gl":"Iniciaches a sesión, benvido.","de":"Sie sind eingeloggt, willkommen zurück!"} ), loginToStart: new Translation( {"en":"Login to answer this question","ca":"Entra per contestar aquesta pregunta","es":"Entra para contestar esta pregunta","nl":"Meld je aan om deze vraag te beantwoorden","fr":"Connectez-vous pour répondre à cette question","gl":"Inicia a sesión para responder esta pregunta","de":"Anmelden, um diese Frage zu beantworten"} ), search: { search: new Translation( {"en":"Search a location","ca":"Cerca una ubicació","es":"Busca una ubicación","nl":"Zoek naar een locatie","fr":"Chercher un lieu","gl":"Procurar unha localización","de":"Einen Ort suchen"} ), diff --git a/Models/Constants.ts b/Models/Constants.ts index 290c686..959198e 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -2,7 +2,7 @@ import { Utils } from "../Utils"; export default class Constants { - public static vNumber = "0.4.7"; + public static vNumber = "0.4.8"; // The user journey states thresholds when a new feature gets unlocked public static userJourney = { diff --git a/State.ts b/State.ts index 2be700e..7a564c5 100644 --- a/State.ts +++ b/State.ts @@ -125,11 +125,11 @@ export default class State { this.layoutToUse.setData(layoutToUse); const zoom = State.asFloat( - QueryParameters.GetQueryParameter("z", "" + layoutToUse.startZoom, "The initial/current zoom level") + QueryParameters.GetQueryParameter("z", "" + layoutToUse?.startZoom, "The initial/current zoom level") .syncWith(LocalStorageSource.Get("zoom"))); - const lat = State.asFloat(QueryParameters.GetQueryParameter("lat", "" + layoutToUse.startLat, "The initial/current latitude") + const lat = State.asFloat(QueryParameters.GetQueryParameter("lat", "" + layoutToUse?.startLat, "The initial/current latitude") .syncWith(LocalStorageSource.Get("lat"))); - const lon = State.asFloat(QueryParameters.GetQueryParameter("lon", "" + layoutToUse.startLon, "The initial/current longitude of the app") + const lon = State.asFloat(QueryParameters.GetQueryParameter("lon", "" + layoutToUse?.startLon, "The initial/current longitude of the app") .syncWith(LocalStorageSource.Get("lon"))); @@ -192,7 +192,7 @@ export default class State { testParam === "true", QueryParameters.GetQueryParameter("oauth_token", undefined, "Used to complete the login"), - layoutToUse.id, + layoutToUse?.id, true ); diff --git a/UI/BigComponents/FullWelcomePaneWithTabs.ts b/UI/BigComponents/FullWelcomePaneWithTabs.ts index b53a59e..d6e8985 100644 --- a/UI/BigComponents/FullWelcomePaneWithTabs.ts +++ b/UI/BigComponents/FullWelcomePaneWithTabs.ts @@ -78,7 +78,6 @@ export default class FullWelcomePaneWithTabs extends UIElement { ]).SetClass("only-on-mobile") .onClick(() => State.state.fullScreenMessage.setData(undefined)); - tabbedPart.SetStyle("overflow-y: auto; max-height: calc( 100vh - 4em);display:block;") this._component = new Combine([tabbedPart, backButton]).SetStyle("width:100%;"); } diff --git a/UI/BigComponents/MoreScreen.ts b/UI/BigComponents/MoreScreen.ts index e0f1ffe..cc68b85 100644 --- a/UI/BigComponents/MoreScreen.ts +++ b/UI/BigComponents/MoreScreen.ts @@ -10,12 +10,17 @@ import {SubtleButton} from "../Base/SubtleButton"; import Translations from "../i18n/Translations"; import * as personal from "../../assets/themes/personalLayout/personalLayout.json" import Constants from "../../Models/Constants"; +import LanguagePicker from "../LanguagePicker"; export default class MoreScreen extends UIElement { + private readonly _onMainScreen: boolean; + + private _component: UIElement; - constructor() { + constructor(onMainScreen: boolean = false) { super(State.state.locationControl); + this._onMainScreen = onMainScreen; this.ListenTo(State.state.osmConnection.userDetails); this.ListenTo(State.state.installedThemes); } @@ -35,7 +40,7 @@ export default class MoreScreen extends UIElement { return undefined; } } - if (layout.id === State.state.layoutToUse.data.id) { + if (layout.id === State.state.layoutToUse.data?.id) { return undefined; } @@ -115,12 +120,23 @@ export default class MoreScreen extends UIElement { } } + let intro : UIElement= tr.intro; + if(this._onMainScreen){ + intro = new Combine([ + + LanguagePicker.CreateLanguagePicker(Translations.t.general.index.SupportedLanguages()) + .SetStyle("position: absolute; right: 1.5em; top: 1.5em;"), + Translations.t.general.index.SetStyle("margin-top: 2em;display:block; margin-bottom: 1em;") + ]) + } + - return new VerticalCombine([ - tr.intro, + this._component = new VerticalCombine([ + intro, new VerticalCombine(els), tr.streetcomplete - ]).Render(); + ]); + return this._component.Render(); } } \ No newline at end of file diff --git a/UI/CustomGenerator/SharePanel.ts b/UI/CustomGenerator/SharePanel.ts index ddb6d13..db479ec 100644 --- a/UI/CustomGenerator/SharePanel.ts +++ b/UI/CustomGenerator/SharePanel.ts @@ -42,7 +42,7 @@ export default class SharePanel extends UIElement { "Copy the json configuration from the 'save-tab', paste it between the 'nowiki'-tags in the Wiki", "Click 'save' to save the wiki page", "Share the link with the url parameter userlayout=wiki:YOURWIKIPAGE, e.g. " + - `https://${window.location.host}?userlayout=${proposedNameEnc}` + `https://${window.location.host}?userlayout=${proposedNameEnc}` ].map(li => `
  • ${li}
  • `), "", diff --git a/UI/i18n/Translation.ts b/UI/i18n/Translation.ts index 4d05a06..d084503 100644 --- a/UI/i18n/Translation.ts +++ b/UI/i18n/Translation.ts @@ -11,7 +11,7 @@ export class Translation extends UIElement { constructor(translations: object, context?: string) { super(Locale.language) - if(translations === undefined){ + if (translations === undefined) { throw `Translation without content (${context})` } let count = 0; @@ -19,11 +19,40 @@ export class Translation extends UIElement { count++; } this.translations = translations; - if(count === 0){ + if (count === 0) { throw `No translations given in the object (${context})` } } + get txt(): string { + if (this.translations["*"]) { + return this.translations["*"]; + } + const txt = this.translations[Translation.forcedLanguage ?? Locale.language.data]; + if (txt !== undefined) { + return txt; + } + const en = this.translations["en"]; + if (en !== undefined) { + return en; + } + for (const i in this.translations) { + return this.translations[i]; // Return a random language + } + console.error("Missing language ", Locale.language.data, "for", this.translations) + return ""; + } + + public SupportedLanguages(): string[] { + const langs = [] + for (const translationsKey in this.translations) { + if(translationsKey === "#"){ + continue; + } + langs.push(translationsKey) + } + return langs; + } public Subs(text: any): Translation { const newTranslations = {}; @@ -57,27 +86,6 @@ export class Translation extends UIElement { } - - get txt(): string { - if (this.translations["*"]) { - return this.translations["*"]; - } - const txt = this.translations[Translation.forcedLanguage ?? Locale.language.data]; - if (txt !== undefined) { - return txt; - } - const en = this.translations["en"]; - if (en !== undefined) { - return en; - } - for (const i in this.translations) { - return this.translations[i]; // Return a random language - } - console.error("Missing language ", Locale.language.data, "for", this.translations) - return ""; - } - - InnerRender(): string { return this.txt } diff --git a/assets/themes/cyclofix/cyclofix.json b/assets/themes/cyclofix/cyclofix.json index d8e6bf4..6660dbc 100644 --- a/assets/themes/cyclofix/cyclofix.json +++ b/assets/themes/cyclofix/cyclofix.json @@ -24,10 +24,10 @@ "maintainer": "MapComplete", "icon": "./assets/themes/cyclofix/logo.svg", "version": "0", - "startLat": 50.8465573, + "startLat": 0, "defaultBackgroundId": "CartoDB.Voyager", - "startLon": 4.3516970, - "startZoom": 16, + "startLon": 0, + "startZoom": 1, "widenFactor": 0.05, "socialImage": "./assets/themes/cyclofix/logo.svg", "layers": [ diff --git a/assets/translations.json b/assets/translations.json index 77cbb72..815d0f9 100644 --- a/assets/translations.json +++ b/assets/translations.json @@ -162,6 +162,13 @@ } }, "general": { + "index": { + "#": "This text is shown above the theme buttons when no theme is loaded", + "en": "

    Welcome to MapComplete

    MapComplete is an OpenStreetMap-viewer and editor, which shows you information about a specific theme.

    Pick a theme below to get started.", + "nl": "

    Welkom bij MapComplete

    MapComplete is een OpenStreetMap applicatie waar informatie over een specifiek thema bekeken en aangepast kan worden.

    Kies hieronder een thema om te beginnen." + }, + + "loginWithOpenStreetMap": { "en": "Login with OpenStreetMap", "ca": "Entra a OpenStreetMap", diff --git a/index.html b/index.html index a1a41a4..9c046e4 100644 --- a/index.html +++ b/index.html @@ -19,7 +19,9 @@ + + @@ -35,7 +37,7 @@ -
    @@ -63,7 +65,6 @@
    Loading MapComplete, hang on...
    -
    diff --git a/index.ts b/index.ts index a62a0b6..0af46eb 100644 --- a/index.ts +++ b/index.ts @@ -6,8 +6,10 @@ import {UIEventSource} from "./Logic/UIEventSource"; import * as $ from "jquery"; import LayoutConfig from "./Customizations/JSON/LayoutConfig"; import {Utils} from "./Utils"; +import MoreScreen from "./UI/BigComponents/MoreScreen"; +import State from "./State"; -let defaultLayout = "bookcases" +let defaultLayout = "" // --------------------- Special actions based on the parameters ----------------- // @ts-ignore if (location.href.startsWith("http://buurtnatuur.be")) { @@ -21,7 +23,7 @@ if (location.href.indexOf("buurtnatuur.be") >= 0) { } const customCssQP = QueryParameters.GetQueryParameter("custom-css", "", "If specified, the custom css from the given link will be loaded additionaly"); -if(customCssQP.data !== undefined && customCssQP.data !== ""){ +if (customCssQP.data !== undefined && customCssQP.data !== "") { Utils.LoadCustomCss(customCssQP.data); } @@ -42,17 +44,16 @@ if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { // ----------------- SELECT THE RIGHT QUESTSET ----------------- - const path = window.location.pathname.split("/").slice(-1)[0]; if (path !== "index.html" && path !== "") { defaultLayout = path; - if(path.endsWith(".html")){ + if (path.endsWith(".html")) { defaultLayout = path.substr(0, path.length - 5); } console.log("Using layout", defaultLayout); } -defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout,"The layout to load into MapComplete").data; -let layoutToUse: LayoutConfig = AllKnownLayouts.allSets[defaultLayout.toLowerCase()] ?? AllKnownLayouts["all"]; +defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout, "The layout to load into MapComplete").data; +let layoutToUse: LayoutConfig = AllKnownLayouts.allSets[defaultLayout.toLowerCase()]; const userLayoutParam = QueryParameters.GetQueryParameter("userlayout", "false"); @@ -73,10 +74,10 @@ if (layoutFromBase64.startsWith("wiki:")) { // Hacky McHackFace has been working here. This'll probably break in the future const startTrigger = "
    "; const start = data.indexOf(startTrigger); - data = data.substr(start, + data = data.substr(start, data.indexOf("
    ") - start) data = data.substr(0, data.lastIndexOf("

    ")) - data = data.substr( data.indexOf("

    ") + 3) + data = data.substr(data.indexOf("

    ") + 3) console.log(data) try { const parsed = JSON.parse(data); @@ -100,8 +101,16 @@ if (layoutFromBase64.startsWith("wiki:")) { } else if (layoutFromBase64 !== "false") { layoutToUse = InitUiElements.LoadLayoutFromHash(userLayoutParam); InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout, location.hash.substr(1)); -} else { +} else if (layoutToUse !== undefined) { + // This is the default case: a builtin theme InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout); +} else { + State.state = new State(undefined); + document.getElementById("messagesboxmobile").remove(); + new MoreScreen(true) + .SetStyle("background: var(--background-color); display: block; margin-left: 5vw; margin-right: 5vw; pointer-events: all;") + .AttachTo("topleft-tools"); + } window.addEventListener('contextmenu', function (e) { // Not compatible with IE < 9 e.preventDefault(); diff --git a/scripts/createLayouts.ts b/scripts/createLayouts.ts index 46ebd91..c5cb73e 100644 --- a/scripts/createLayouts.ts +++ b/scripts/createLayouts.ts @@ -227,7 +227,7 @@ function createLandingPage(layout: LayoutConfig) { } let output = template - .replace(`./manifest.manifest`, `./${enc(layout.id)}.webmanifest`) + .replace("./manifest.manifest",`${enc(layout.id)}.webmanifest`) .replace("", og) .replace(/.+?<\/title>/, `<title>${ogTitle}`) .replace("Loading MapComplete, hang on...", `Loading MapComplete theme ${ogTitle}...`) @@ -251,7 +251,7 @@ if (! existsSync(generatedDir)) { mkdirSync(generatedDir) } -const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap"] +const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap","custom"] const all = AllKnownLayouts.allSets; let wikiPage = "{|class=\"wikitable sortable\"\n" + @@ -278,12 +278,12 @@ for (const layoutName in all) { const manifestLocation = encodeURIComponent(layout.id.toLowerCase()) + ".webmanifest"; writeFile(manifestLocation, manif, err); + // Create a landing page for the given theme const landing = createLandingPage(layout); writeFile(enc(layout.id) + ".html", landing, err) wikiPage += "\n"+generateWikiEntry(layout); } - wikiPage += "\n|}" writeFile(generatedDir + "/wikiIndex", wikiPage, (err) => {