From ba44024dd91baec2ddfdc4574026bc0ee92247b9 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 13 Nov 2020 23:58:11 +0100 Subject: [PATCH] Fixes, surveillance cams v0.1 --- Customizations/AllKnownLayouts.ts | 6 ++- InitUiElements.ts | 4 +- Logic/Web/QueryParameters.ts | 23 +++++++--- README.md | 46 ++++++++++++++++++- State.ts | 46 +++++++++++-------- UI/Image/DeleteImage.ts | 3 ++ UI/Image/ImageUploadFlow.ts | 4 ++ UI/Popup/TagRenderingAnswer.ts | 24 ++++------ .../surveillance_cameras.json | 26 ++++++++++- index.ts | 20 +------- 10 files changed, 137 insertions(+), 65 deletions(-) rename assets/{layers => themes/surveillance_cameras}/surveillance_cameras.json (89%) diff --git a/Customizations/AllKnownLayouts.ts b/Customizations/AllKnownLayouts.ts index e00ca6c21..5c1c0a02e 100644 --- a/Customizations/AllKnownLayouts.ts +++ b/Customizations/AllKnownLayouts.ts @@ -15,10 +15,11 @@ 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 * as drinking_water from "../assets/themes/drinking_water/drinking_water.json" -import LayerConfig from "./JSON/LayerConfig"; -import SharedLayers from "./SharedLayers"; +import * as surveillance_cameras from "../assets/themes/surveillance_cameras/surveillance_cameras.json" import * as personal from "../assets/themes/personalLayout/personalLayout.json" +import LayerConfig from "./JSON/LayerConfig"; import LayoutConfig from "./JSON/LayoutConfig"; +import SharedLayers from "./SharedLayers"; export class AllKnownLayouts { @@ -60,6 +61,7 @@ export class AllKnownLayouts { new LayoutConfig(widths), new LayoutConfig(buurtnatuur), new LayoutConfig(bike_monitoring_stations), + new LayoutConfig(surveillance_cameras) ]; diff --git a/InitUiElements.ts b/InitUiElements.ts index 4b9a85503..8310b0c71 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -442,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.defaultBackgroundId); + const queryParam = QueryParameters.GetQueryParameter("background", State.state.layoutToUse.data.defaultBackgroundId, "The id of the background layer to start with"); queryParam.addCallbackAndRun((selectedId: string) => { const available = State.state.availableBackgroundLayers.data; @@ -483,7 +483,7 @@ export class InitUiElements { const flayer: FilteredLayer = FilteredLayer.fromDefinition(layer, generateInfo); flayers.push(flayer); - QueryParameters.GetQueryParameter("layer-" + layer.id, "true") + QueryParameters.GetQueryParameter("layer-" + layer.id, "true", "Wehter or not layer "+layer.id+" is shown") .map((str) => str !== "false", [], (b) => b.toString()) .syncWith( flayer.isDisplayed diff --git a/Logic/Web/QueryParameters.ts b/Logic/Web/QueryParameters.ts index 235ff7b61..821c163c2 100644 --- a/Logic/Web/QueryParameters.ts +++ b/Logic/Web/QueryParameters.ts @@ -5,20 +5,22 @@ import {UIEventSource} from "../UIEventSource"; export class QueryParameters { - private static order: string [] = ["layout","test","z","lat","lon"]; + private static order: string [] = ["layout", "test", "z", "lat", "lon"]; private static knownSources = {}; private static initialized = false; private static defaults = {} - - private static addOrder(key){ - if(this.order.indexOf(key) < 0){ + + private static documentation = {} + + private static addOrder(key) { + if (this.order.indexOf(key) < 0) { this.order.push(key) } } private static init() { - - if(this.initialized){ + + if (this.initialized) { return; } this.initialized = true; @@ -63,6 +65,7 @@ export class QueryParameters { if(!this.initialized){ this.init(); } + QueryParameters.documentation[key] = documentation; if (deflt !== undefined) { QueryParameters.defaults[key] = deflt; } @@ -76,4 +79,12 @@ export class QueryParameters { return source; } + public static GenerateQueryParameterDocs(): string { + const docs = []; + for (const key in QueryParameters.documentation) { + docs.push("**" + key + "**: " + QueryParameters.documentation[key] + " (default value: _" + QueryParameters.defaults[key] + "_)") + } + return docs.join("\n\n"); + } + } \ No newline at end of file diff --git a/README.md b/README.md index 3f527120b..1a2eed364 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ A theme has translations into the preset.json (`assets/themes/themename/themenam 1. Modify `"language"` to contain the new language, e.g. `"language": "nl"` becomes `"language": ["nl", "en"]` 2. Add extra strings to the texts. If it used to be a single-language theme, one can replace the strings, e.g.: `"description": "Welcome to Open Bookcase Map"` to `"description": {"en": "Welcome to Open Bookcase Map", "nl": "Welkom bij de OpenBoekenruilkastenKaart", "fr": "Bienvenue sûr la carte des petites bibliotheques"}`. If the correct language is not found, it'll fallback to another supported language. -3. If you notice missing translations in the core of MapComplete, fork this project, open [the file containing all translations](https://github.com/pietervdvn/MapComplete/blob/master/UI/i18n/Translations.ts), add add a language string there +3. If you notice missing translations in the core of MapComplete, fork this project, open [the file containing all translations](https://github.com/pietervdvn/MapComplete/blob/master/assets/translations.json), add add a language string there 4. Send a pull request to update the languages, I'll gladly add it! It doesn't have to be a complete translation from the start ;) ### Adding your theme to the repository @@ -165,6 +165,50 @@ Whenever a change is made -even adding a single tag- the change is uploaded into Note that changesets are closed automatically after one hour of inactivity, so we don't have to worry about closing them. +### Query parameters + +By adding extra query parameters, more options are available to influence: + +**test**: If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org (default value: _false_) + +**layout**: The layout to load into MapComplete (default value: _bookcases_) + +**userlayout**: undefined (default value: _false_) + +**layer-control-toggle**: Wether or not the layer control is shown (default value: _false_) + +**tab**: The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >200 changesets) (default value: _0_) + +**z**: The initial/current zoom level (default value: _1_) + +**lat**: The initial/current latitude (default value: _0_) + +**lon**: The initial/current longitude of the app (default value: _0_) + +**fs-userbadge**: Disables/Enables the userbadge (and thus disables login capabilities) (default value: _true_) + +**fs-search**: Disables/Enables the search bar (default value: _true_) + +**fs-layers**: Disables/Enables the layer control (default value: _true_) + +**fs-add-new**: Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place) (default value: _true_) + +**fs-welcome-message**: undefined (default value: _true_) + +**fs-iframe**: Disables/Enables the iframe-popup (default value: _false_) + +**fs-more-quests**: Disables/Enables the 'More Quests'-tab in the welcome message (default value: _true_) + +**fs-share-screen**: Disables/Enables the 'Share-screen'-tab in the welcome message (default value: _true_) + +**fs-geolocation**: Disables/Enables the geolocation button (default value: _true_) + +**oauth_token**: Used to complete the login (default value: _undefined_) + +**background**: The id of the background layer to start with (default value: _undefined_) + +**layer-bookcases**: Wehter or not layer bookcases is shown (default value: _true_) index.ts:104:8 + # Privacy Privacy is important, we try to leak as little information as possible. diff --git a/State.ts b/State.ts index 0bbb77925..5d7b63fba 100644 --- a/State.ts +++ b/State.ts @@ -115,10 +115,10 @@ export default class State { public layoutDefinition: string; public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; - public layerControlIsOpened: UIEventSource = QueryParameters.GetQueryParameter("layer-control-toggle", "false") + public layerControlIsOpened: UIEventSource = QueryParameters.GetQueryParameter("layer-control-toggle", "false", "Wether or not the layer control is shown") .map((str) => str !== "false", [], b => "" + b) - public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0").map( + public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0", `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${State.userJourney.mapCompleteHelpUnlock} changesets)`).map( str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n ); @@ -138,11 +138,11 @@ export default class State { }) } this.zoom = asFloat( - QueryParameters.GetQueryParameter("z", "" + layoutToUse.startZoom) + QueryParameters.GetQueryParameter("z", "" + layoutToUse.startZoom, "The initial/current zoom level") .syncWith(LocalStorageSource.Get("zoom"))); - this.lat = asFloat(QueryParameters.GetQueryParameter("lat", "" + layoutToUse.startLat) + this.lat = asFloat(QueryParameters.GetQueryParameter("lat", "" + layoutToUse.startLat, "The initial/current latitude") .syncWith(LocalStorageSource.Get("lat"))); - this.lon = asFloat(QueryParameters.GetQueryParameter("lon", "" + layoutToUse.startLon) + this.lon = asFloat(QueryParameters.GetQueryParameter("lon", "" + layoutToUse.startLon, "The initial/current longitude of the app") .syncWith(LocalStorageSource.Get("lon"))); @@ -165,8 +165,8 @@ export default class State { }); - function featSw(key: string, deflt: (layout: LayoutConfig) => boolean, documentation?: string): UIEventSource { - const queryParameterSource = QueryParameters.GetQueryParameter(key, undefined); + function featSw(key: string, deflt: (layout: LayoutConfig) => boolean, documentation: string): UIEventSource { + const queryParameterSource = QueryParameters.GetQueryParameter(key, undefined, documentation); // I'm so sorry about someone trying to decipher this // It takes the current layout, extracts the default value for this query paramter. A query parameter event source is then retreived and flattened @@ -180,20 +180,30 @@ export default class State { this.featureSwitchUserbadge = featSw("fs-userbadge", (layoutToUse) => layoutToUse?.enableUserBadge ?? true, - "Disables the userbadge (and thus disables login capabilities)"); - 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?.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); - this.featureSwitchShareScreen = featSw("fs-share-screen", (layoutToUse) => layoutToUse?.enableShareScreen ?? true); - this.featureSwitchGeolocation = featSw("fs-geolocation", (layoutToUse) => layoutToUse?.enableGeolocation ?? true); + "Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode."); + this.featureSwitchSearch = featSw("fs-search", (layoutToUse) => layoutToUse?.enableSearch ?? true, + "Disables/Enables the search bar"); + this.featureSwitchLayers = featSw("fs-layers", (layoutToUse) => layoutToUse?.enableLayers ?? true, + "Disables/Enables the layer control"); + this.featureSwitchAddNew = featSw("fs-add-new", (layoutToUse) => layoutToUse?.enableAddNewPoints ?? true, + "Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place)"); + this.featureSwitchWelcomeMessage = featSw("fs-welcome-message", () => true, + "Disables/enables the help menu or welcome message"); + this.featureSwitchIframe = featSw("fs-iframe", () => false, + "Disables/Enables the iframe-popup"); + this.featureSwitchMoreQuests = featSw("fs-more-quests", (layoutToUse) => layoutToUse?.enableMoreQuests ?? true, + "Disables/Enables the 'More Quests'-tab in the welcome message"); + this.featureSwitchShareScreen = featSw("fs-share-screen", (layoutToUse) => layoutToUse?.enableShareScreen ?? true, + "Disables/Enables the 'Share-screen'-tab in the welcome message"); + this.featureSwitchGeolocation = featSw("fs-geolocation", (layoutToUse) => layoutToUse?.enableGeolocation ?? true, + "Disables/Enables the geolocation button"); - const testParam = QueryParameters.GetQueryParameter("test", "false").data; + const testParam = QueryParameters.GetQueryParameter("test", "false", + "If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org").data; this.osmConnection = new OsmConnection( testParam === "true", - QueryParameters.GetQueryParameter("oauth_token", undefined), + QueryParameters.GetQueryParameter("oauth_token", undefined, + "Used to complete the login"), layoutToUse.id, true ); diff --git a/UI/Image/DeleteImage.ts b/UI/Image/DeleteImage.ts index b59af0603..7e5a2c1bb 100644 --- a/UI/Image/DeleteImage.ts +++ b/UI/Image/DeleteImage.ts @@ -42,6 +42,9 @@ export default class DeleteImage extends UIElement { } InnerRender(): string { + if(!State.state.featureSwitchUserbadge.data){ + return ""; + } const value = this.tags.data[this.key]; if (value === undefined || value === "") { diff --git a/UI/Image/ImageUploadFlow.ts b/UI/Image/ImageUploadFlow.ts index 0e8815a39..2fb61bc8d 100644 --- a/UI/Image/ImageUploadFlow.ts +++ b/UI/Image/ImageUploadFlow.ts @@ -51,6 +51,10 @@ export class ImageUploadFlow extends UIElement { } InnerRender(): string { + + if(!State.state.featureSwitchUserbadge.data){ + return ""; + } const t = Translations.t.image; if (State.state.osmConnection.userDetails === undefined) { diff --git a/UI/Popup/TagRenderingAnswer.ts b/UI/Popup/TagRenderingAnswer.ts index 8c9f6ddb7..f560bf293 100644 --- a/UI/Popup/TagRenderingAnswer.ts +++ b/UI/Popup/TagRenderingAnswer.ts @@ -9,25 +9,11 @@ import {SubstitutedTranslation} from "../SpecialVisualizations"; export default class TagRenderingAnswer extends UIElement { private _tags: UIEventSource; private _configuration: TagRenderingConfig; - private _content: UIElement; constructor(tags: UIEventSource, configuration: TagRenderingConfig) { super(tags); this._tags = tags; this._configuration = configuration; - const self = this; - tags.addCallbackAndRun(tags => { - if (tags === undefined) { - self._content = undefined - return; - } - const tr = this._configuration.GetRenderValue(tags); - if (tr === undefined) { - self._content = undefined - return - } - self._content = new SubstitutedTranslation(tr, self._tags) - }) } InnerRender(): string { @@ -36,10 +22,16 @@ export default class TagRenderingAnswer extends UIElement { return ""; } } - if(this._content === undefined){ + + const tags = this._tags.data; + if (tags === undefined) { return ""; } - return this._content.Render(); + const tr = this._configuration.GetRenderValue(tags); + if (tr === undefined) { + return ""; + } + return new SubstitutedTranslation(tr, this._tags).Render(); } } \ No newline at end of file diff --git a/assets/layers/surveillance_cameras.json b/assets/themes/surveillance_cameras/surveillance_cameras.json similarity index 89% rename from assets/layers/surveillance_cameras.json rename to assets/themes/surveillance_cameras/surveillance_cameras.json index 46126a56f..c2af520cf 100644 --- a/assets/layers/surveillance_cameras.json +++ b/assets/themes/surveillance_cameras/surveillance_cameras.json @@ -156,8 +156,8 @@ "key": "surveillance:type" }, "render": { - "en": " Surveills a {surveillance:type}", - "nl": "Bewaakt een {surveillance:type}" + "en": " Surveills a {surveillance:zone}", + "nl": "Bewaakt een {surveillance:zone}" }, "mappings": [ { @@ -193,6 +193,28 @@ "nl": "Bewaakt een ingang" } }, + { + "if": { + "and": [ + "surveillance:zone=corridor" + ] + }, + "then": { + "en": "Surveills a corridor", + "nl": "Bewaakt een gang" + } + }, + { + "if": { + "and": [ + "surveillance:zone=public_transport_platform" + ] + }, + "then": { + "en": "Surveills a public tranport platform", + "nl": "Bewaakt een perron of bushalte" + } + }, { "if": { "and": [ diff --git a/index.ts b/index.ts index 712f57072..62b53f833 100644 --- a/index.ts +++ b/index.ts @@ -4,7 +4,6 @@ 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" @@ -54,23 +53,7 @@ if (path !== "index.html" && path !== "") { defaultLayout = path.substr(0, path.length - 5); console.log("Using layout", defaultLayout); } - -// 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 : LayoutConfig= AllKnownLayouts.allSets[k]; - const possibleParts = (layout.locationContains ?? []); - for (const locationMatch of possibleParts) { - if (locationMatch === "") { - continue - } - if (window.location.href.toLowerCase().indexOf(locationMatch.toLowerCase()) >= 0) { - defaultLayout = layout.name; - } - } -} - -defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout).data; - +defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout,"The layout to load into MapComplete").data; let layoutToUse: LayoutConfig = AllKnownLayouts.allSets[defaultLayout.toLowerCase()] ?? AllKnownLayouts["all"]; @@ -118,3 +101,4 @@ if (layoutFromBase64.startsWith("wiki:")) { InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout); } +// console.log(QueryParameters.GenerateQueryParameterDocs())