From e0f9a934687ba0150e07446ee85dd2f4a2d4f7be Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 24 Jul 2020 01:12:57 +0200 Subject: [PATCH] Cleanup of code --- Customizations/Layout.ts | 6 +- Logic/LayerUpdater.ts | 1 + Quests.ts | 76 ----------------- UI/AddButton.ts | 148 --------------------------------- UI/Base/CollapseButton.ts | 43 ---------- UI/{Base => Input}/CheckBox.ts | 8 +- UI/LayerSelection.ts | 2 +- Utils.ts | 17 ++++ assets/help.svg | 71 ++++++++++++++++ index.css | 78 ++++++++++------- index.html | 5 +- index.ts | 107 +++++++++++------------- 12 files changed, 193 insertions(+), 369 deletions(-) delete mode 100644 Quests.ts delete mode 100644 UI/AddButton.ts delete mode 100644 UI/Base/CollapseButton.ts rename UI/{Base => Input}/CheckBox.ts (76%) create mode 100644 Utils.ts create mode 100644 assets/help.svg diff --git a/Customizations/Layout.ts b/Customizations/Layout.ts index eb13be3..bbeccf4 100644 --- a/Customizations/Layout.ts +++ b/Customizations/Layout.ts @@ -96,13 +96,11 @@ export class WelcomeMessage extends UIElement { } InnerRender(): string { - return "
" + + return "" + this.description.Render() + - "
"+ (this.userDetails.data.loggedIn ? this.welcomeBack : this.plzLogIn).Render() + - "
"+ this.tail.Render() + - "
" + "" ; /* diff --git a/Logic/LayerUpdater.ts b/Logic/LayerUpdater.ts index 5478e89..0a70ac0 100644 --- a/Logic/LayerUpdater.ts +++ b/Logic/LayerUpdater.ts @@ -41,6 +41,7 @@ export class LayerUpdater { map.Location.addCallback(function () { self.update(); }); + self.update(); } diff --git a/Quests.ts b/Quests.ts deleted file mode 100644 index e649fe0..0000000 --- a/Quests.ts +++ /dev/null @@ -1,76 +0,0 @@ -import {QuestionDefinition} from "./Logic/Question"; - - -export class Quests { - - - static hasFee = QuestionDefinition.radioQuestionSimple("Moet men betalen om deze toiletten te gebruiken?", 10, - "fee", - [{text: "ja", value: "yes"}, {text: "nee", value: "no"}] - ); - - static toiletsWheelChairs = QuestionDefinition.radioQuestionSimple("Zijn deze toiletten rolstoeltoegankelijk?", 20, - "wheelchair", - [{text: "ja", value: "yes"}, {text: "nee", value: "no"}] - ).addUnrequiredTag("toilets:position", "urinals"); - - static toiletsChangingTable = QuestionDefinition.radioQuestionSimple("Is er een luiertafel beschikbaar?", 20, - "changing_table", - [{text: "ja", value: "yes"}, {text: "nee", value: "no"}] - ) - // Urinals are often a pitlatrine/something very poor where no changing table is - .addUnrequiredTag("toilets:position", "urinals").addUnrequiredTag("toilets:position", "urinal"); - - static toiletsChangingTableLocation = QuestionDefinition.radioAndTextQuestion("Waar bevindt de luiertafel zich?", 5, - "changing_table", - [{text: "In de vrouwentoiletten", value: "female_toilet"}, - {text: "In de mannentoiletten", value: "male_toilet"}, - {text: "In de rolstoeltoegangkelijke toiletten", value: "wheelchair_toilet"}, - {text: "In de aparte, speciaal voorziene ruimte", value: "dedicated_room"}, - {text: "In de genderneutrale toiletten", value: "unisex_toilet"}] - ) - .addRequiredTag("changing_table", "yes"); - - - static toiletsPosition = QuestionDefinition.radioQuestionSimple("Wat voor toiletten zijn dit?", 1, - "toilets:position", - [{text: "Enkel urinoirs", value: "urinals"}, - {text: "Enkel 'gewone' toiletten waar men op gaat zitten", value: "seated"}, - {text: "Er zijn zowel urinoirs als zittoiletten", value: "seated;urinals"}]); - - - - static accessNatureReserve = QuestionDefinition.radioQuestionSimple( - "Is dit gebied toegankelijk voor het publiek?", - 10, - "access", - [ - {text: "Nee, dit is afgesloten", value: "no"}, - {text: "Nee, dit is een privaat terrein", value: "no"}, - {text: "Hoewel het een privebos is, kan men er toch in", value: "permissive"}, - {text: "Enkel tijdens activiteiten of met een gids", value: "guided"}, - {text: "Ja, het is gewoon toegankelijk", value: "yes"} - ] - ).addUnrequiredTag("seamark:type", "restricted_area"); - - static nameOf(name: string) : QuestionDefinition { - return QuestionDefinition.noNameOrNameQuestion("Wat is de officiƫle naam van dit " + name + "?
" + - "Veel gebieden hebben geen naam. Duid dit dan ook zo aan.", - "Dit " + name + " heeft geen naam", 20); - } - - static operator = - QuestionDefinition.radioAndTextQuestion( - "Wie is de beheerder van dit gebied?", - 1, - "operator", - [{text: "Natuurpunt", value: "Natuurpunt"}, - {text: "Het Agenschap voor Natuur en Bos", value: "Agentschap Natuur en Bos"}, - {text: "Een prive-eigenaar", value: "private"} - ] - ).addUnrequiredTag("access", "private") - .addUnrequiredTag("access", "no"); - - - -} \ No newline at end of file diff --git a/UI/AddButton.ts b/UI/AddButton.ts deleted file mode 100644 index 3b493a9..0000000 --- a/UI/AddButton.ts +++ /dev/null @@ -1,148 +0,0 @@ -import {UIEventSource} from "./UIEventSource"; -import {UIElement} from "./UIElement"; -import {Basemap} from "../Logic/Basemap"; -import {Changes} from "../Logic/Changes"; -import L from "leaflet"; -import {Tag} from "../Logic/TagsFilter"; -import {FilteredLayer} from "../Logic/FilteredLayer"; - -export class AddButton extends UIElement { - - public curentAddSelection: UIEventSource = new UIEventSource(""); - private zoomlevel: UIEventSource<{ zoom: number }>; - - private readonly SELECTING_POI = "selecting_POI"; - private readonly PLACING_POI = "placing_POI"; - - private changes: Changes; - - /*State is one of: - * "": the default stated - * "select_POI": show a 'select which POI to add' query (skipped if only one option exists) - * "placing_point": shown while adding a point - * "" - */ - private state: UIEventSource = new UIEventSource(""); - private _options: { name: string; icon: string; tags: Tag[]; layerToAddTo: FilteredLayer }[]; - - - constructor( - basemap: Basemap, - changes: Changes, - options: { - name: string, - icon: string, - tags: Tag[], - layerToAddTo: FilteredLayer - }[]) { - super(undefined); - - this.zoomlevel = basemap.Location; - this.ListenTo(this.zoomlevel); - this._options = options; - this.ListenTo(this.curentAddSelection); - this.ListenTo(this.state); - this.state.setData(this.SELECTING_POI); - this.changes = changes; - - const self = this; - - - basemap.map.on("click", function (e) { - const location = e.latlng; - console.log("Clicked at ", location) - self.HandleClick(location.lat, location.lng) - } - ); - - basemap.map.on("mousemove", function(){ - if (self.state.data === self.PLACING_POI) { - - let icon = "crosshair"; - for (const option of self._options) { - if (option.name === self.curentAddSelection.data && option.icon !== undefined) { - icon = 'url("' + option.icon + '") 32 32 ,crosshair'; - console.log("Cursor icon: ", icon) - } - } - document.getElementById('leafletDiv').style.cursor = icon; - - } else { - // @ts-ignore - document.getElementById('leafletDiv').style.cursor = ''; - } - }); - - - } - - private HandleClick(lat: number, lon: number): void { - this.state.setData(this.SELECTING_POI); - console.log("Handling click", lat, lon, this.curentAddSelection.data); - for (const option of this._options) { - if (this.curentAddSelection.data === option.name) { - console.log("PLACING a ", option); - - let feature = this.changes.createElement(option.tags, lat, lon); - option.layerToAddTo.AddNewElement(feature); - - return; - } - } - } - - protected InnerRender(): string { - - if (this.zoomlevel.data.zoom < 19) { - return "Zoom in om een punt toe te voegen" - } - - if (this.state.data === this.SELECTING_POI) { - var html = "
"; - for (const option of this._options) { - //
"; - } - html += "
"; - return html; - } - - if (this.state.data === this.PLACING_POI) { - return "
Klik op de kaart om een nieuw punt toe te voegen
" + - "
Klik hier om toevoegen te annuleren
" - } - - if (this.curentAddSelection.data === "") { - return "Voeg een punt toe..." - } - return "Annuleer"; - } - - InnerUpdate(htmlElement: HTMLElement) { - const self = this; - - htmlElement.onclick = function (event) { - // @ts-ignore - if(event.consumed){ - return; - } - if (self.state.data === self.PLACING_POI) { - self.state.setData(self.SELECTING_POI); - } - - } - - const buttons = htmlElement.getElementsByClassName('addPOIoption'); - // @ts-ignore - for (const button of buttons) { - button.onclick = function (event) { - self.curentAddSelection.setData(button.value); - self.state.setData(self.PLACING_POI); - event.consumed = true; - } - } - } - - -} \ No newline at end of file diff --git a/UI/Base/CollapseButton.ts b/UI/Base/CollapseButton.ts deleted file mode 100644 index 752131e..0000000 --- a/UI/Base/CollapseButton.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {UIElement} from "../UIElement"; -import {UIEventSource} from "../UIEventSource"; - - -export class CollapseButton extends UIElement { - public isCollapsed = new UIEventSource(false); - - constructor(idToCollapse: string) { - super(undefined); - this.ListenTo(this.isCollapsed); - this.isCollapsed.addCallback((collapse) => { - const el = document.getElementById(idToCollapse); - if (el === undefined || el === null) { - console.log("Element not found") - return; - } - if (collapse) { - el.style.height = "3.5em"; - el.style.width = "15em"; - } else { - el.style.height = "auto"; - el.style.width = "auto"; - } - }); - - const self = this; - this.onClick(() => { - self.isCollapsed.setData(!self.isCollapsed.data); - }) - - } - - protected InnerRender(): string { - const up = './assets/arrow-up.svg'; - const down = './assets/arrow-down.svg'; - let arrow = up; - if (this.isCollapsed.data) { - arrow = down; - } - return `collapse`; - } - -} \ No newline at end of file diff --git a/UI/Base/CheckBox.ts b/UI/Input/CheckBox.ts similarity index 76% rename from UI/Base/CheckBox.ts rename to UI/Input/CheckBox.ts index c912425..5c5c120 100644 --- a/UI/Base/CheckBox.ts +++ b/UI/Input/CheckBox.ts @@ -2,6 +2,7 @@ import {UIElement} from "../UIElement"; import {UIEventSource} from "../UIEventSource"; import { FilteredLayer } from "../../Logic/FilteredLayer"; import Translations from "../../UI/i18n/Translations"; +import instantiate = WebAssembly.instantiate; export class CheckBox extends UIElement{ @@ -11,9 +12,10 @@ export class CheckBox extends UIElement{ private readonly _showEnabled: string|UIElement; private readonly _showDisabled: string|UIElement; - constructor(showEnabled: string|UIElement, showDisabled: string|UIElement, data: UIEventSource = undefined) { + constructor(showEnabled: string | UIElement, showDisabled: string | UIElement, data: UIEventSource | boolean = false) { super(undefined); - this._data = data ?? new UIEventSource(false); + this._data = + data instanceof UIEventSource ? data : new UIEventSource(data ?? false); this.ListenTo(this._data); this._showEnabled = showEnabled; this._showDisabled = showDisabled; @@ -21,7 +23,7 @@ export class CheckBox extends UIElement{ this.onClick(() => { self._data.setData(!self._data.data); }) - + } InnerRender(): string { diff --git a/UI/LayerSelection.ts b/UI/LayerSelection.ts index e9408d4..021ef76 100644 --- a/UI/LayerSelection.ts +++ b/UI/LayerSelection.ts @@ -1,6 +1,6 @@ import { UIElement } from "./UIElement"; import { FilteredLayer } from "../Logic/FilteredLayer"; -import { CheckBox } from "./Base/CheckBox"; +import { CheckBox } from "./Input/CheckBox"; import Combine from "./Base/Combine"; export class LayerSelection extends UIElement{ diff --git a/Utils.ts b/Utils.ts new file mode 100644 index 0000000..253159d --- /dev/null +++ b/Utils.ts @@ -0,0 +1,17 @@ +export class Utils { + + /** + * Gives a clean float, or undefined if parsing fails + * @param str + */ + static asFloat(str): number { + if (str) { + const i = parseFloat(str); + if (isNaN(i)) { + return undefined; + } + return i; + } + return undefined; + } +} \ No newline at end of file diff --git a/assets/help.svg b/assets/help.svg new file mode 100644 index 0000000..092ffad --- /dev/null +++ b/assets/help.svg @@ -0,0 +1,71 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/index.css b/index.css index 9563c08..02b83e0 100644 --- a/index.css +++ b/index.css @@ -101,9 +101,9 @@ form { #usertext { - width: auto; - margin:0; - + width: max-content; + margin: 0; + padding: 0.9em; padding-left: 4.7em; /* Should be half of profile-pic's width + actual padding (same as padding-right)*/ padding-right: 1.5em; @@ -225,7 +225,7 @@ form { } -@media only screen and (max-height: 600px) { +@media only screen and (max-height: 300px) { /* Landscape */ #userbadge-and-search { display: inline-block; @@ -267,44 +267,58 @@ form { display: none; /*Only shown on small screens*/ } -#welcomeMessage { - max-width: 35em; - padding: 0; - padding-top: 1em; - padding-bottom: 1em; -} - -#collapseButton { +.collapse-button { position: absolute; - right: 1em; - background-color: white; - margin: 1.5em; - border: 2px solid black; - border-radius: 2em; - padding: 0.5em; + background-color: #e5f5ff; + width: 3.5em; + border-top-left-radius: 2em; + border-bottom-left-radius: 2em; display: inline-block; - width: 1em; - height: 1em; + height:calc(100% - 8em); } -#collapseButton img { - width: 1em; - height: 1em; +.collapse-button .collapse-button-img{ + background-color: #e5f5ff; } -e -#messagesbox-wrapper { +.open-button { + width: 2em; + border-top-left-radius: 2em; + border-bottom-left-radius: 2em; } +.collapse-button-img { + border-radius: 50%; + box-sizing: border-box; + display: inline-block; + padding: 1em; + background-color: white; +} + +.collapse-button-img img{ + width: 1.5em; + padding: 0.5em; + margin: 0; + padding: 0; +} + +#welcomeMessage { + display: inline-block; + background-color: white; + padding: 1em; + margin-left: 3.5em; + padding-left: 1em; + padding-bottom: 2em; + border-radius: 2em; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + width: 100%; + max-width: 25vw; +} #messagesbox { /*Only shown on big screens*/ - padding: 2em; - padding-top: 1em; - padding-bottom: 1em; - z-index: 5000; - background-color: white; - border-radius: 2em; + padding: 0; pointer-events: all; } @@ -405,7 +419,7 @@ e border-radius: 15px 15px 0 0; } -@media only screen and (max-width: 600px), only screen and (max-height: 600px) { +@media only screen and (max-width: 600px), only screen and (max-height: 300px) { #messagesbox-wrapper { display: none; } diff --git a/index.html b/index.html index 96d9b95..b0fca73 100644 --- a/index.html +++ b/index.html @@ -36,10 +36,7 @@

-
-
-
-
+
diff --git a/index.ts b/index.ts index cfea672..281c018 100644 --- a/index.ts +++ b/index.ts @@ -20,7 +20,7 @@ import {VariableUiElement} from "./UI/Base/VariableUIElement"; import {SearchAndGo} from "./UI/SearchAndGo"; import {CollapseButton} from "./UI/Base/CollapseButton"; import {AllKnownLayouts} from "./Customizations/AllKnownLayouts"; -import {CheckBox} from "./UI/Base/CheckBox"; +import {CheckBox} from "./UI/Input/CheckBox"; import Translations from "./UI/i18n/Translations"; import Locale from "./UI/i18n/Locale"; import {Layout, WelcomeMessage} from "./Customizations/Layout"; @@ -30,9 +30,10 @@ import {LayerSelection} from "./UI/LayerSelection"; import Combine from "./UI/Base/Combine"; import {Img} from "./UI/Img"; import {QueryParameters} from "./Logic/QueryParameters"; +import {Utils} from "./Utils"; -// --------------------- Read the URL parameters ----------------- +// --------------------- Special actions based on the parameters ----------------- // @ts-ignore if (location.href.startsWith("http://buurtnatuur.be")) { @@ -40,13 +41,11 @@ if (location.href.startsWith("http://buurtnatuur.be")) { window.location.replace("https://buurtnatuur.be"); } - -let dryRun = false; - if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { // Set to true if testing and changes should NOT be saved - dryRun = true; + const testing = QueryParameters.GetQueryParameter("test"); + testing.setData((testing.data === undefined) + "") // If you have a testfile somewhere, enable this to spoof overpass // This should be hosted independantly, e.g. with `cd assets; webfsd -p 8080` + a CORS plugin to disable cors rules //Overpass.testUrl = "http://127.0.0.1:8080/streetwidths.geojson"; @@ -55,7 +54,6 @@ if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { // ----------------- SELECT THE RIGHT QUESTSET ----------------- - let defaultLayout = "walkbybrussels" @@ -74,16 +72,10 @@ for (const k in AllKnownLayouts.allSets) { } defaultLayout = QueryParameters.GetQueryParameter("layout").data ?? defaultLayout; -dryRun = QueryParameters.GetQueryParameter("test").data === "true"; -const layoutToUse: Layout = AllKnownLayouts.allSets[defaultLayout]; +const layoutToUse: Layout = AllKnownLayouts.allSets[defaultLayout] ?? AllKnownLayouts["all"]; console.log("Using layout: ", layoutToUse.name); -document.title = layoutToUse.title.InnerRender(); -Locale.language.addCallback(e => { - document.title = layoutToUse.title.InnerRender(); -}) - // ----------------- Setup a few event sources ------------- @@ -102,31 +94,19 @@ const fullScreenMessage = new UIEventSource(undefined); // The latest element that was selected - used to generate the right UI at the right place const selectedElement = new UIEventSource<{ feature: any }>(undefined); - -function clean(str) : number{ - if (str) { - const i = parseFloat(str); - if (isNaN(i)) { - return undefined; - } - return i; - } - return undefined; -} - const zoom = QueryParameters.GetQueryParameter("z"); const lat = QueryParameters.GetQueryParameter("lat"); const lon = QueryParameters.GetQueryParameter("lon"); + const locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({ - zoom: clean(zoom.data) ?? layoutToUse.startzoom, - lat: clean(lat.data) ?? layoutToUse.startLat, - lon: clean(lon.data) ?? layoutToUse.startLon + zoom: Utils.asFloat(zoom.data) ?? layoutToUse.startzoom, + lat: Utils.asFloat(lat.data) ?? layoutToUse.startLat, + lon: Utils.asFloat(lon.data) ?? layoutToUse.startLon }); locationControl.addCallback((latlonz) => { zoom.setData(latlonz.zoom.toString()); - lat.setData(latlonz.lat.toString().substr(0,6)); lon.setData(latlonz.lon.toString().substr(0,6)); }) @@ -134,7 +114,9 @@ locationControl.addCallback((latlonz) => { // ----------------- Prepare the important objects ----------------- -const osmConnection = new OsmConnection(dryRun); +const osmConnection = new OsmConnection( + QueryParameters.GetQueryParameter("test").data === "true" +); Locale.language.syncWith(osmConnection.GetPreference("language")); @@ -212,7 +194,7 @@ for (const layer of layoutToUse.layers) { const layerUpdater = new LayerUpdater(bm, minZoom, flayers); -// --------------- Setting up filter ui -------- +// --------------- Setting up layer selection ui -------- const closedFilterButton = ``; @@ -229,28 +211,39 @@ const backgroundMapPicker = new Combine([new DropDown(`Background map`, baseLaye const layerSelection = new Combine([`

Maplayers

`, new LayerSelection(flayers)]); let layerControl = backgroundMapPicker; if (flayers.length > 1) { - layerControl = new Combine([layerSelection, backgroundMapPicker); + layerControl = new Combine([layerSelection, backgroundMapPicker]); } new CheckBox(layerControl, closedFilterButton).AttachTo("filter__selection"); -// ------------------ Setup various UI elements ------------ +// ------------------ Setup various other UI elements ------------ + +document.title = layoutToUse.title.InnerRender(); + +Locale.language.addCallback(e => { + document.title = layoutToUse.title.InnerRender(); +}) +let languagePicker = new DropDown("", layoutToUse.supportedLanguages.map(lang => { + return {value: lang, shown: lang} + } +), Locale.language); new StrayClickHandler(bm, selectedElement, fullScreenMessage, () => { - return new SimpleAddUI(bm.Location, - bm.LastClickLocation, - changes, - selectedElement, - layerUpdater.runningQuery, - osmConnection.userDetails, - addButtons); + return new SimpleAddUI(bm.Location, + bm.LastClickLocation, + changes, + selectedElement, + layerUpdater.runningQuery, + osmConnection.userDetails, + addButtons); } ); /** - * Show the questions and information for the selected element on the fullScreen + * Show the questions and information for the selected element + * This is given to the div which renders fullscreen on mobile devices */ selectedElement.addCallback((feature) => { const data = feature.feature.properties; @@ -278,13 +271,7 @@ selectedElement.addCallback((feature) => { ); -const pendingChanges = new PendingChanges( - changes, secondsTillChangesAreSaved,); - -let languagePicker = new DropDown("", layoutToUse.supportedLanguages.map(lang => { - return {value: lang, shown: lang} - } -), Locale.language); +const pendingChanges = new PendingChanges(changes, secondsTillChangesAreSaved,); new UserBadge(osmConnection.userDetails, pendingChanges, @@ -294,12 +281,20 @@ new UserBadge(osmConnection.userDetails, new SearchAndGo(bm).AttachTo("searchbox"); +/* new CollapseButton("messagesbox") - .AttachTo("collapseButton"); -new WelcomeMessage(layoutToUse, osmConnection).AttachTo("messagesbox"); -fullScreenMessage.setData( - new WelcomeMessage(layoutToUse, osmConnection) -); + .AttachTo("collapseButton");*/ +const welcome = new WelcomeMessage(layoutToUse, osmConnection).onClick(() => { +}); + +const help = new FixedUiElement(`
collapse
`); +new CheckBox( + new Combine([ + new Combine(["", help, ""]), + welcome]), + new Combine(["", help, ""]) + , true +).AttachTo("messagesbox") new FullScreenMessageBoxHandler(fullScreenMessage, () => { @@ -324,9 +319,5 @@ osmConnection.registerActivateOsmAUthenticationClass(); new GeoLocationHandler(bm).AttachTo("geolocate-button"); -// --------------- Send a ping to start various action -------- - -locationControl.ping(); -