"
+ ""
;
/*
diff --git a/Logic/LayerUpdater.ts b/Logic/LayerUpdater.ts
index 5478e8944..0a70ac0b2 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 e649fe055..000000000
--- 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 3b493a949..000000000
--- 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 = "";
- 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 752131e2b..000000000
--- 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 ``;
- }
-
-}
\ 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 c91242587..5c5c120de 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 e9408d4fa..021ef769d 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 000000000..253159dde
--- /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 000000000..092ffad25
--- /dev/null
+++ b/assets/help.svg
@@ -0,0 +1,71 @@
+
+
+
+
diff --git a/index.css b/index.css
index 9563c08f0..02b83e0b0 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 96d9b95be..b0fca7302 100644
--- a/index.html
+++ b/index.html
@@ -36,10 +36,7 @@
-
-
-
-
+
diff --git a/index.ts b/index.ts
index cfea6720e..281c01897 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(`
`);
+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();
-