From ff1690e3075528d9625bf7f987614fd4b8e0d23a Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Mon, 13 Jul 2020 16:18:04 +0200 Subject: [PATCH 1/8] Hide edit buttons when not logged in, css tweaks --- Customizations/AllKnownLayouts.ts | 5 +++-- Customizations/Layers/Bookcases.ts | 2 +- Customizations/Layout.ts | 9 +-------- Customizations/Layouts/Bookcases.ts | 1 + Customizations/Layouts/Groen.ts | 2 ++ Customizations/TagRendering.ts | 13 ++++++++++++- Logic/Changes.ts | 2 +- UI/Image/ImageCarousel.ts | 15 ++++++++++----- index.css | 3 +-- index.html | 9 --------- index.ts | 18 ++++++++++++++++++ 11 files changed, 50 insertions(+), 29 deletions(-) diff --git a/Customizations/AllKnownLayouts.ts b/Customizations/AllKnownLayouts.ts index 68173c8..9a8728e 100644 --- a/Customizations/AllKnownLayouts.ts +++ b/Customizations/AllKnownLayouts.ts @@ -5,13 +5,14 @@ import {Statues} from "./Layouts/Statues"; import {Bookcases} from "./Layouts/Bookcases"; import Cyclofix from "./Layouts/Cyclofix"; import {All} from "./Layouts/All"; +import {Layout} from "./Layout"; export class AllKnownLayouts { public static allSets: any = AllKnownLayouts.AllLayouts(); - private static AllLayouts() { + private static AllLayouts() : any{ const all = new All(); - const layouts = [ + const layouts : Layout[] = [ new Groen(), new GRB(), new Cyclofix(), diff --git a/Customizations/Layers/Bookcases.ts b/Customizations/Layers/Bookcases.ts index acc9d65..52e0b86 100644 --- a/Customizations/Layers/Bookcases.ts +++ b/Customizations/Layers/Bookcases.ts @@ -145,7 +145,7 @@ export class Bookcases extends LayerDefinition { new TagRenderingOptions({ freeform: { key: "description", - renderTemplate: "Beschrijving door de uitbater
{description}", + renderTemplate: "Beschrijving door de uitbater:
{description}", template: "$$$", } }) diff --git a/Customizations/Layout.ts b/Customizations/Layout.ts index 9ff0e4c..7a5b880 100644 --- a/Customizations/Layout.ts +++ b/Customizations/Layout.ts @@ -16,6 +16,7 @@ export class Layout { public startLat: number; public welcomeTail: string; + public locationContains: string[]; constructor( name: string, @@ -41,13 +42,5 @@ export class Layout { this.welcomeTail = welcomeTail; } -/* - - - static statues = new Layout( - - ); - -*/ } diff --git a/Customizations/Layouts/Bookcases.ts b/Customizations/Layouts/Bookcases.ts index 7d02aab..833150b 100644 --- a/Customizations/Layouts/Bookcases.ts +++ b/Customizations/Layouts/Bookcases.ts @@ -23,5 +23,6 @@ export class Bookcases extends Layout{ " of door je " + " aan te melden.

", "Klik op een boekenruilkastje om vragen te beantwoorden"); + this.locationContains= ["Bookcases.html", "Bookcase.html","bookcase"] } } \ No newline at end of file diff --git a/Customizations/Layouts/Groen.ts b/Customizations/Layouts/Groen.ts index 8e7f047..7f3d0f9 100644 --- a/Customizations/Layouts/Groen.ts +++ b/Customizations/Layouts/Groen.ts @@ -47,5 +47,7 @@ export class Groen extends Layout { "Als je inlogt, komt er een tweede cookie bij met je inloggegevens." + "" ); + + this.locationContains = ["buurtnatuur.be"] } } \ No newline at end of file diff --git a/Customizations/TagRendering.ts b/Customizations/TagRendering.ts index bd99ed4..a02f2a0 100644 --- a/Customizations/TagRendering.ts +++ b/Customizations/TagRendering.ts @@ -11,6 +11,7 @@ import {UIRadioButtonWithOther} from "../UI/Base/UIRadioButtonWithOther"; import {VariableUiElement} from "../UI/Base/VariableUIElement"; import {TagDependantUIElement, TagDependantUIElementConstructor} from "./UIElementConstructor"; import {OnlyShowIfConstructor} from "./OnlyShowIf"; +import {UserDetails} from "../Logic/OsmConnection"; export class TagRenderingOptions implements TagDependantUIElementConstructor { @@ -111,6 +112,7 @@ class TagRendering extends UIElement implements TagDependantUIElement { private _priority: number; + private _userDetails: UIEventSource; Priority(): number { return this._priority; @@ -162,6 +164,9 @@ class TagRendering extends UIElement implements TagDependantUIElement { this.ListenTo(this._questionSkipped); this.ListenTo(this._editMode); + this._userDetails = changes.login.userDetails; + this.ListenTo(this._userDetails); + this._question = options.question; this._priority = options.priority ?? 0; this._primer = options.primer ?? ""; @@ -397,8 +402,14 @@ class TagRendering extends UIElement implements TagDependantUIElement { if (html == "") { return ""; } + let editButton = ""; + if(this._userDetails.data.loggedIn){ + editButton = this._editButton.Render(); + } + return "" + - "" + html + "" + this._editButton.Render() + + "" + html + "" + + editButton + ""; } diff --git a/Logic/Changes.ts b/Logic/Changes.ts index b93e1f0..de58a76 100644 --- a/Logic/Changes.ts +++ b/Logic/Changes.ts @@ -13,7 +13,7 @@ export class Changes { private static _nextId = -1; // New assined ID's are negative - private readonly login: OsmConnection; + public readonly login: OsmConnection; public readonly _allElements: ElementStorage; private _pendingChanges: { elementId: string, key: string, value: string }[] = []; // Gets reset on uploadAll diff --git a/UI/Image/ImageCarousel.ts b/UI/Image/ImageCarousel.ts index 82627f1..f8f69c9 100644 --- a/UI/Image/ImageCarousel.ts +++ b/UI/Image/ImageCarousel.ts @@ -7,6 +7,7 @@ import {VerticalCombine} from "../Base/VerticalCombine"; import {Changes} from "../../Logic/Changes"; import {VariableUiElement} from "../Base/VariableUIElement"; import {ConfirmDialog} from "../ConfirmDialog"; +import {UserDetails} from "../../Logic/OsmConnection"; export class ImageCarousel extends UIElement { @@ -18,10 +19,13 @@ export class ImageCarousel extends UIElement { private readonly _deleteButton: UIElement; private readonly _isDeleted: UIElement; + + private readonly _userDetails : UIEventSource; constructor(tags: UIEventSource, changes: Changes) { super(tags); - + this._userDetails = changes.login.userDetails; + const self = this; this.searcher = new ImageSearcher(tags, changes); @@ -40,8 +44,11 @@ export class ImageCarousel extends UIElement { const showDeleteButton = this.slideshow._currentSlide.map((i) => { + if(!self._userDetails.data.loggedIn){ + return false; + } return self.searcher.IsDeletable(self.searcher.data[i]); - }, [this.searcher]); + }, [this.searcher, this._userDetails]); this.slideshow._currentSlide.addCallback(() => { showDeleteButton.ping(); // This pings the showDeleteButton, which indicates that it has to hide it's subbuttons }) @@ -57,8 +64,7 @@ export class ImageCarousel extends UIElement { "Afbeelding verwijderen", "Terug", deleteCurrent, - () => { - }, + () => { }, 'delete-image-confirm', 'delete-image-cancel'); @@ -75,7 +81,6 @@ export class ImageCarousel extends UIElement { this._isDeleted = new VariableUiElement( mapping ) - // .HideOnEmpty(true); this.searcher._deletedImages.addCallback(() => { this.slideshow._currentSlide.ping(); diff --git a/index.css b/index.css index 07cf49b..c86b574 100644 --- a/index.css +++ b/index.css @@ -573,7 +573,7 @@ form { /***************** Info box (box containing features and questions ******************/ .leaflet-popup-content { - width: 25vw !important; + width: 40em !important; } .featureinfobox { @@ -669,7 +669,6 @@ form { background-color: #e5f5ff; padding: 1em; border-radius: 1em; - margin-right: 1em; font-size: larger; } diff --git a/index.html b/index.html index e340617..16c5387 100644 --- a/index.html +++ b/index.html @@ -48,15 +48,6 @@ - - - - - - - - - diff --git a/index.ts b/index.ts index 45fd058..252cf5c 100644 --- a/index.ts +++ b/index.ts @@ -21,6 +21,7 @@ import {VariableUiElement} from "./UI/Base/VariableUIElement"; import {SearchAndGo} from "./UI/SearchAndGo"; import {CollapseButton} from "./UI/Base/CollapseButton"; import {AllKnownLayouts} from "./Customizations/AllKnownLayouts"; +import {All} from "./Customizations/Layouts/All"; @@ -50,6 +51,23 @@ if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { let defaultQuest = "buurtnatuur" + +for (const k in AllKnownLayouts.allSets) { + const layout = AllKnownLayouts.allSets[k]; + const possibleParts = layout.locationContains ?? []; + console.log(layout.locationContains) + for (const locationMatch of possibleParts) { + if(locationMatch === ""){ + continue + } + console.log(layout.name," -> ", locationMatch, window.location.href.indexOf(locationMatch)) + if(window.location.href.toLowerCase().indexOf(locationMatch.toLowerCase()) >= 0){ + defaultQuest = layout.name; + console.log("Detected a default by URL: ", layout.name, "matches", locationMatch) + } + } +} + if (window.location.search) { const params = window.location.search.substr(1).split("&"); const paramDict: any = {}; From 5970883adce401487cc7f2bf3a46d1307b38ab79 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Tue, 14 Jul 2020 15:49:42 +0200 Subject: [PATCH 2/8] Small explanation for description --- Customizations/Questions/DescriptionQuestion.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/Customizations/Questions/DescriptionQuestion.ts b/Customizations/Questions/DescriptionQuestion.ts index df6f0ba..46f7263 100644 --- a/Customizations/Questions/DescriptionQuestion.ts +++ b/Customizations/Questions/DescriptionQuestion.ts @@ -7,6 +7,7 @@ export class DescriptionQuestion extends TagRenderingOptions{ super({ question: "Zijn er bijzonderheden die we moeten weten over dit "+category+"?
" + "Je hoeft niet te herhalen wat je net hebt aangeduid.
" + + "Een naam wordt in de volgende stap gevraagd.
" + "Voel je vrij om dit veld over te slaan.
", freeform:{ key:"description:0", From 54a01dfbeff7aaab07f38a544df5d83bac603083 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Tue, 14 Jul 2020 20:18:44 +0200 Subject: [PATCH 3/8] Make imageCarousel fit in with other elements (to make images optional or lower in the popup), add ghost bike popup --- Customizations/Layers/BikeParkings.ts | 4 +- Customizations/Layers/BikePumps.ts | 14 +-- Customizations/Layers/Bos.ts | 2 + Customizations/Layers/GhostBike.ts | 36 ++++++++ Customizations/Layers/NatureReserves.ts | 2 + Customizations/Layers/Park.ts | 2 + Customizations/Layouts/Cyclofix.ts | 3 +- .../Questions/{FixedName.ts => FixedText.ts} | 2 +- Logic/OsmConnection.ts | 24 ++++- README.md | 3 + UI/FeatureInfoBox.ts | 34 ++----- UI/Image/ImageCarousel.ts | 35 ++++++- UI/Image/ImageCarouselWithUpload.ts | 71 ++++++++++++++ assets/ghost_bike.svg | 92 +++++++++++++++++++ index.ts | 22 +---- 15 files changed, 289 insertions(+), 57 deletions(-) create mode 100644 Customizations/Layers/GhostBike.ts rename Customizations/Questions/{FixedName.ts => FixedText.ts} (79%) create mode 100644 UI/Image/ImageCarouselWithUpload.ts create mode 100644 assets/ghost_bike.svg diff --git a/Customizations/Layers/BikeParkings.ts b/Customizations/Layers/BikeParkings.ts index 2f032c2..7dc1bd9 100644 --- a/Customizations/Layers/BikeParkings.ts +++ b/Customizations/Layers/BikeParkings.ts @@ -2,7 +2,7 @@ import {LayerDefinition} from "../LayerDefinition"; import {And, Or, Tag} from "../../Logic/TagsFilter"; import {OperatorTag} from "../Questions/OperatorTag"; import * as L from "leaflet"; -import FixedName from "../Questions/FixedName"; +import FixedText from "../Questions/FixedText"; import { BikeParkingType } from "../Questions/BikeParkingType"; export class BikeParkings extends LayerDefinition { @@ -26,7 +26,7 @@ export class BikeParkings extends LayerDefinition { this.minzoom = 13; this.style = this.generateStyleFunction(); - this.title = new FixedName("fietsparking"); + this.title = new FixedText("fietsparking"); this.elementsToShow = [ new OperatorTag(), new BikeParkingType() diff --git a/Customizations/Layers/BikePumps.ts b/Customizations/Layers/BikePumps.ts index 4da60d6..d214f13 100644 --- a/Customizations/Layers/BikePumps.ts +++ b/Customizations/Layers/BikePumps.ts @@ -3,7 +3,8 @@ import {And, Or, Tag} from "../../Logic/TagsFilter"; import {OperatorTag} from "../Questions/OperatorTag"; import * as L from "leaflet"; import { PumpManual } from "../Questions/PumpManual"; -import FixedName from "../Questions/FixedName"; +import FixedText from "../Questions/FixedText"; +import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload"; export class BikePumps extends LayerDefinition { @@ -14,24 +15,25 @@ export class BikePumps extends LayerDefinition { this.overpassFilter = new Or([ new And([ - new Tag("amenity", "compressed_air"), - new Tag("bicycle", "yes"), + new Tag("amenity", "bicycle_repair_station"), + new Tag("service:bicycle:pump", "yes"), ]) ] ); this.newElementTags = [ - new Tag("amenity", "compressed_air"), - new Tag("bicycle", "yes"), + new Tag("amenity", "bicycle_repair_station"), + new Tag("service:bicycle:pump", "yes"), // new Tag("fixme", "Toegevoegd met MapComplete, geometry nog uit te tekenen") ]; this.maxAllowedOverlapPercentage = 10; this.minzoom = 13; this.style = this.generateStyleFunction(); - this.title = new FixedName("pomp"); + this.title = new FixedText("Pomp"); this.elementsToShow = [ + new ImageCarouselWithUploadConstructor(), // new NameQuestion(), // new AccessTag(), new OperatorTag(), diff --git a/Customizations/Layers/Bos.ts b/Customizations/Layers/Bos.ts index b9b809c..a396550 100644 --- a/Customizations/Layers/Bos.ts +++ b/Customizations/Layers/Bos.ts @@ -7,6 +7,7 @@ import {TagRenderingOptions} from "../TagRendering"; import {NameQuestion} from "../Questions/NameQuestion"; import {NameInline} from "../Questions/NameInline"; import {DescriptionQuestion} from "../Questions/DescriptionQuestion"; +import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload"; export class Bos extends LayerDefinition { @@ -33,6 +34,7 @@ export class Bos extends LayerDefinition { this.style = this.generateStyleFunction(); this.title = new NameInline("bos"); this.elementsToShow = [ + new ImageCarouselWithUploadConstructor(), new NameQuestion(), new AccessTag(), new OperatorTag(), diff --git a/Customizations/Layers/GhostBike.ts b/Customizations/Layers/GhostBike.ts new file mode 100644 index 0000000..f88d274 --- /dev/null +++ b/Customizations/Layers/GhostBike.ts @@ -0,0 +1,36 @@ +import {LayerDefinition} from "../LayerDefinition"; +import {Tag} from "../../Logic/TagsFilter"; +import {FixedUiElement} from "../../UI/Base/FixedUiElement"; +import {TagRenderingOptions} from "../TagRendering"; +import FixedText from "../Questions/FixedText"; +import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload"; +import L from "leaflet"; + +export class GhostBike extends LayerDefinition { + constructor() { + super(); + this.name = "ghost bike"; + this.overpassFilter = new Tag("memorial", "ghost_bike") + this.title = new FixedText("Ghost bike"); + + this.elementsToShow = [ + new FixedText("A ghost bike is a memorial for a cyclist who died in a traffic accident," + + " in the form of a white bicycle placed permanently near the accident location."), + new ImageCarouselWithUploadConstructor(), + + + ]; + + this.style = (tags: any) => { + return { + color: "#000000", + icon: L.icon({ + iconUrl: 'assets/ghost_bike.svg', + iconSize: [40, 40], + iconAnchor: [20, 20], + }) + } + }; + + } +} \ No newline at end of file diff --git a/Customizations/Layers/NatureReserves.ts b/Customizations/Layers/NatureReserves.ts index f6b1abf..5d49292 100644 --- a/Customizations/Layers/NatureReserves.ts +++ b/Customizations/Layers/NatureReserves.ts @@ -6,6 +6,7 @@ import {OperatorTag} from "../Questions/OperatorTag"; import {NameQuestion} from "../Questions/NameQuestion"; import {NameInline} from "../Questions/NameInline"; import {DescriptionQuestion} from "../Questions/DescriptionQuestion"; +import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload"; export class NatureReserves extends LayerDefinition { @@ -23,6 +24,7 @@ export class NatureReserves extends LayerDefinition { this.title = new NameInline("natuurreservaat"); this.style = this.generateStyleFunction(); this.elementsToShow = [ + new ImageCarouselWithUploadConstructor(), new NameQuestion(), new AccessTag(), new OperatorTag(), diff --git a/Customizations/Layers/Park.ts b/Customizations/Layers/Park.ts index aee1a23..e2814a7 100644 --- a/Customizations/Layers/Park.ts +++ b/Customizations/Layers/Park.ts @@ -7,6 +7,7 @@ import {TagRenderingOptions} from "../TagRendering"; import {NameQuestion} from "../Questions/NameQuestion"; import {NameInline} from "../Questions/NameInline"; import {DescriptionQuestion} from "../Questions/DescriptionQuestion"; +import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload"; export class Park extends LayerDefinition { @@ -58,6 +59,7 @@ export class Park extends LayerDefinition { this.style = this.generateStyleFunction(); this.title = new NameInline("park"); this.elementsToShow = [ + new ImageCarouselWithUploadConstructor(), new NameQuestion(), this.accessByDefault, this.operatorByDefault, diff --git a/Customizations/Layouts/Cyclofix.ts b/Customizations/Layouts/Cyclofix.ts index 7ba29ad..88b08f7 100644 --- a/Customizations/Layouts/Cyclofix.ts +++ b/Customizations/Layouts/Cyclofix.ts @@ -2,13 +2,14 @@ import {Layout} from "../Layout"; import {GrbToFix} from "../Layers/GrbToFix"; import { BikePumps } from "../Layers/BikePumps"; import { BikeParkings } from "../Layers/BikeParkings"; +import {GhostBike} from "../Layers/GhostBike"; export default class Cyclofix extends Layout { constructor() { super( "pomp", "Grb import fix tool", - [new BikePumps(), new BikeParkings()], + [new BikePumps(), new BikeParkings(), new GhostBike()], 15, 51.2083, 3.2279, diff --git a/Customizations/Questions/FixedName.ts b/Customizations/Questions/FixedText.ts similarity index 79% rename from Customizations/Questions/FixedName.ts rename to Customizations/Questions/FixedText.ts index 0210f9c..178fb53 100644 --- a/Customizations/Questions/FixedName.ts +++ b/Customizations/Questions/FixedText.ts @@ -1,6 +1,6 @@ import { TagRenderingOptions } from "../TagRendering"; -export default class FixedName extends TagRenderingOptions { +export default class FixedText extends TagRenderingOptions { constructor(category: string) { super({ mappings: [ diff --git a/Logic/OsmConnection.ts b/Logic/OsmConnection.ts index 45d5bce..e35d254 100644 --- a/Logic/OsmConnection.ts +++ b/Logic/OsmConnection.ts @@ -13,7 +13,6 @@ export class UserDetails { public osmConnection: OsmConnection; public dryRun: boolean; home: { lon: number; lat: number }; - } export class OsmConnection { @@ -121,6 +120,27 @@ export class OsmConnection { } public preferences = new UIEventSource({}); + public preferenceSources : any = {} + + public GetPreference(key: string) : UIEventSource{ + if(this.preferenceSources[key] !== undefined){ + return this.preferenceSources[key]; + } + const pref = new UIEventSource(undefined); + pref.addCallback((v) => { + this.SetPreference(key, v); + }); + + this.preferences.addCallback((prefs) => { + if (prefs[key] !== undefined) { + pref.setData(prefs[key]); + } + }); + + this.preferenceSources[key] = pref; + return pref; + } + private UpdatePreferences() { const self = this; this.auth.xhr({ @@ -142,7 +162,7 @@ export class OsmConnection { }); } - public SetPreference(k:string, v:string) { + private SetPreference(k:string, v:string) { if(!this.userDetails.data.loggedIn){ console.log("Not saving preference: user not logged in"); return; diff --git a/README.md b/README.md index 594264c..9994bee 100644 --- a/README.md +++ b/README.md @@ -94,3 +94,6 @@ Trash icon by Dave Gandy, CC-BY-SA https://commons.wikimedia.org/wiki/File:Home-icon.svg Home icon by Timothy Miller, CC-BY-SA 3.0 + +https://commons.wikimedia.org/wiki/File:Map_icons_by_Scott_de_Jonge_-_bicycle-store.svg +Bicycle logo, Scott de Jonge \ No newline at end of file diff --git a/UI/FeatureInfoBox.ts b/UI/FeatureInfoBox.ts index b358417..2c7832c 100644 --- a/UI/FeatureInfoBox.ts +++ b/UI/FeatureInfoBox.ts @@ -15,29 +15,25 @@ import {TagDependantUIElement} from "../Customizations/UIElementConstructor"; export class FeatureInfoBox extends UIElement { private _tagsES: UIEventSource; + private _changes: Changes; + private _userDetails: UIEventSource; private _title: UIElement; private _osmLink: UIElement; - - - private _questions: QuestionPicker; - - private _changes: Changes; - private _userDetails: UIEventSource; - private _imageElement: ImageCarousel; - private _pictureUploader: UIElement; private _wikipedialink: UIElement; - private _infoboxes: TagDependantUIElement[]; + + private _infoboxes: TagDependantUIElement[]; + private _questions: QuestionPicker; + constructor( tagsES: UIEventSource, title: TagRenderingOptions, elementsToShow: TagRenderingOptions[], changes: Changes, - userDetails: UIEventSource, - preferedPictureLicense: UIEventSource + userDetails: UIEventSource ) { super(tagsES); this._tagsES = tagsES; @@ -45,9 +41,9 @@ export class FeatureInfoBox extends UIElement { this._userDetails = userDetails; this.ListenTo(userDetails); - this._imageElement = new ImageCarousel(this._tagsES, changes); - + this._infoboxes = []; + elementsToShow = elementsToShow ?? [] for (const tagRenderingOption of elementsToShow) { this._infoboxes.push( tagRenderingOption.construct(this._tagsES, this._changes)); @@ -60,11 +56,9 @@ export class FeatureInfoBox extends UIElement { ) this._title = new TagRenderingOptions(title.options).construct(this._tagsES, this._changes); - this._osmLink =new OsmLink().construct(this._tagsES, this._changes); this._wikipedialink = new WikipediaLink().construct(this._tagsES, this._changes); - this._pictureUploader = new OsmImageUploadHandler(tagsES, userDetails, preferedPictureLicense, - changes, this._imageElement.slideshow).getUI(); + } @@ -110,10 +104,6 @@ export class FeatureInfoBox extends UIElement { "" + "
" + - - this._imageElement.Render() + - this._pictureUploader.Render() + - new VerticalCombine(info, "infobox-information ").Render() + questionsHtml + @@ -126,8 +116,6 @@ export class FeatureInfoBox extends UIElement { Activate() { super.Activate(); - this._imageElement.Activate(); - this._pictureUploader.Activate(); for (const infobox of this._infoboxes) { infobox.Activate(); } @@ -135,8 +123,6 @@ export class FeatureInfoBox extends UIElement { Update() { super.Update(); - this._imageElement.Update(); - this._pictureUploader.Update(); this._title.Update(); for (const infobox of this._infoboxes) { infobox.Update(); diff --git a/UI/Image/ImageCarousel.ts b/UI/Image/ImageCarousel.ts index f8f69c9..9d4e1fd 100644 --- a/UI/Image/ImageCarousel.ts +++ b/UI/Image/ImageCarousel.ts @@ -8,8 +8,29 @@ import {Changes} from "../../Logic/Changes"; import {VariableUiElement} from "../Base/VariableUIElement"; import {ConfirmDialog} from "../ConfirmDialog"; import {UserDetails} from "../../Logic/OsmConnection"; +import {TagDependantUIElement, TagDependantUIElementConstructor} from "../../Customizations/UIElementConstructor"; + +export class ImageCarouselConstructor implements TagDependantUIElementConstructor{ + IsKnown(properties: any): boolean { + return true; + } + + IsQuestioning(properties: any): boolean { + return false; + } + + Priority(): number { + return 0; + } + + construct(tags: UIEventSource, changes: Changes): TagDependantUIElement { + return new ImageCarousel(tags, changes); + } + +} + +export class ImageCarousel extends TagDependantUIElement { -export class ImageCarousel extends UIElement { private readonly searcher: ImageSearcher; @@ -98,6 +119,18 @@ export class ImageCarousel extends UIElement { ""; } + IsKnown(): boolean { + return true; + } + + IsQuestioning(): boolean { + return false; + } + + Priority(): number { + return 0; + } + InnerUpdate(htmlElement: HTMLElement) { super.InnerUpdate(htmlElement); this._deleteButton.Update(); diff --git a/UI/Image/ImageCarouselWithUpload.ts b/UI/Image/ImageCarouselWithUpload.ts new file mode 100644 index 0000000..231044a --- /dev/null +++ b/UI/Image/ImageCarouselWithUpload.ts @@ -0,0 +1,71 @@ +import {TagDependantUIElement, TagDependantUIElementConstructor} from "../../Customizations/UIElementConstructor"; +import {ImageCarousel} from "./ImageCarousel"; +import {OsmImageUploadHandler} from "../../Logic/OsmImageUploadHandler"; +import {UIEventSource} from "../UIEventSource"; +import {Changes} from "../../Logic/Changes"; +import {UserDetails} from "../../Logic/OsmConnection"; +import {ImageUploadFlow} from "../ImageUploadFlow"; + +export class ImageCarouselWithUploadConstructor implements TagDependantUIElementConstructor{ + IsKnown(properties: any): boolean { + return true; + } + + IsQuestioning(properties: any): boolean { + return false; + } + + Priority(): number { + return 0; + } + + construct(tags: UIEventSource, changes: Changes): TagDependantUIElement { + return new ImageCarouselWithUpload(tags, changes); + } +} + +class ImageCarouselWithUpload extends TagDependantUIElement { + private _imageElement: ImageCarousel; + private _pictureUploader: ImageUploadFlow; + + constructor(tags: UIEventSource, changes: Changes) { + super(tags); + this._imageElement = new ImageCarousel(tags, changes); + const userDetails = changes.login.userDetails; + const license = changes.login.GetPreference( "mapcomplete-pictures-license"); + this._pictureUploader = new OsmImageUploadHandler(tags, + userDetails, license, + changes, this._imageElement.slideshow).getUI(); + + } + + protected InnerRender(): string { + return this._imageElement.Render() + + this._pictureUploader.Render(); + } + + Activate() { + super.Activate(); + this._imageElement.Activate(); + this._pictureUploader.Activate(); + } + + Update() { + super.Update(); + this._imageElement.Update(); + this._pictureUploader.Update(); + } + + IsKnown(): boolean { + return true; + } + + IsQuestioning(): boolean { + return false; + } + + Priority(): number { + return 0; + } + +} \ No newline at end of file diff --git a/assets/ghost_bike.svg b/assets/ghost_bike.svg new file mode 100644 index 0000000..1befcb7 --- /dev/null +++ b/assets/ghost_bike.svg @@ -0,0 +1,92 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/index.ts b/index.ts index 252cf5c..73b8cea 100644 --- a/index.ts +++ b/index.ts @@ -102,7 +102,6 @@ const leftMessage = new UIEventSource<() => UIElement>(undefined); const selectedElement = new UIEventSource(undefined); -const preferedPictureLicense = new UIEventSource(undefined); const locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({ zoom: questSetToRender.startzoom, @@ -137,21 +136,6 @@ const bm = new Basemap("leafletDiv", locationControl, new VariableUiElement( )); -// ------------- Tie together user settings and UI ----------- - - -const picturesPrefName = "mapcomplete-pictures-license"; -preferedPictureLicense.addCallback((license) => { - osmConnection.SetPreference(picturesPrefName, license); -}); - -osmConnection.preferences.addCallback((prefs) => { - if (prefs[picturesPrefName] !== undefined) { - preferedPictureLicense.setData(prefs[picturesPrefName]); - } -}) - - // ------------- Setup the layers ------------------------------- const addButtons: { @@ -175,8 +159,7 @@ for (const layer of questSetToRender.layers) { layer.title, layer.elementsToShow, changes, - osmConnection.userDetails, - preferedPictureLicense + osmConnection.userDetails ) }; @@ -228,8 +211,7 @@ selectedElement.addCallback((data) => { layer.title, layer.elementsToShow, changes, - osmConnection.userDetails, - preferedPictureLicense + osmConnection.userDetails )); break; } From 05c3710e8d953e115476c32515cfd56befe5e6f2 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 15 Jul 2020 10:47:01 +0200 Subject: [PATCH 4/8] Small fixes (in loading the settings) --- Customizations/Layers/BikePumps.ts | 54 +++++++++--------------------- Logic/OsmConnection.ts | 3 +- UI/Base/DropDownUI.ts | 3 ++ 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/Customizations/Layers/BikePumps.ts b/Customizations/Layers/BikePumps.ts index d214f13..d53f6d8 100644 --- a/Customizations/Layers/BikePumps.ts +++ b/Customizations/Layers/BikePumps.ts @@ -13,24 +13,34 @@ export class BikePumps extends LayerDefinition { this.name = "pomp"; this.icon = "./assets/bike_pump.svg"; - this.overpassFilter = new Or([ + this.overpassFilter = new And([ new Tag("amenity", "bicycle_repair_station"), new Tag("service:bicycle:pump", "yes"), - ]) - ] - ); + ]); this.newElementTags = [ new Tag("amenity", "bicycle_repair_station"), new Tag("service:bicycle:pump", "yes"), - // new Tag("fixme", "Toegevoegd met MapComplete, geometry nog uit te tekenen") ]; + this.maxAllowedOverlapPercentage = 10; this.minzoom = 13; - this.style = this.generateStyleFunction(); + const self = this; + this.style = (properties: any) => { + + return { + color: "#00bb00", + icon: new L.icon({ + iconUrl: self.icon, + iconSize: [40, 40] + }) + }; + }; + + this.title = new FixedText("Pomp"); this.elementsToShow = [ new ImageCarouselWithUploadConstructor(), @@ -43,37 +53,5 @@ export class BikePumps extends LayerDefinition { } - private generateStyleFunction() { - const self = this; - return function (properties: any) { - // let questionSeverity = 0; - // for (const qd of self.elementsToShow) { - // if (qd.IsQuestioning(properties)) { - // questionSeverity = Math.max(questionSeverity, qd.options.priority ?? 0); - // } - // } - - // let colormapping = { - // 0: "#00bb00", - // 1: "#00ff00", - // 10: "#dddd00", - // 20: "#ff0000" - // }; - - // let colour = colormapping[questionSeverity]; - // while (colour == undefined) { - // questionSeverity--; - // colour = colormapping[questionSeverity]; - // } - - return { - color: "#00bb00", - icon: new L.icon({ - iconUrl: self.icon, - iconSize: [40, 40] - }) - }; - }; - } } \ No newline at end of file diff --git a/Logic/OsmConnection.ts b/Logic/OsmConnection.ts index e35d254..686fb16 100644 --- a/Logic/OsmConnection.ts +++ b/Logic/OsmConnection.ts @@ -126,7 +126,7 @@ export class OsmConnection { if(this.preferenceSources[key] !== undefined){ return this.preferenceSources[key]; } - const pref = new UIEventSource(undefined); + const pref = new UIEventSource(this.preferences[key]); pref.addCallback((v) => { this.SetPreference(key, v); }); @@ -169,6 +169,7 @@ export class OsmConnection { } if (this.preferences.data[k] === v) { + console.log("Not updating preference", k, " to ", v, "not changed"); return; } console.log("Updating preference", k, " to ", v); diff --git a/UI/Base/DropDownUI.ts b/UI/Base/DropDownUI.ts index 521068a..208ea85 100644 --- a/UI/Base/DropDownUI.ts +++ b/UI/Base/DropDownUI.ts @@ -41,6 +41,9 @@ export class DropDownUI extends UIElement { InnerUpdate() { const self = this; const e = document.getElementById("dropdown-" + this.id); + if(e === null){ + return; + } // @ts-ignore if (this.selectedElement.data !== e.value) { // @ts-ignore From d293429c68c7f436760898c32de84d34d3160916 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 15 Jul 2020 10:53:00 +0200 Subject: [PATCH 5/8] Fix preference loading --- Logic/OsmConnection.ts | 6 ++++-- assets/Buurtnatuur-Welkom.txt | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 assets/Buurtnatuur-Welkom.txt diff --git a/Logic/OsmConnection.ts b/Logic/OsmConnection.ts index 686fb16..66a4719 100644 --- a/Logic/OsmConnection.ts +++ b/Logic/OsmConnection.ts @@ -126,7 +126,9 @@ export class OsmConnection { if(this.preferenceSources[key] !== undefined){ return this.preferenceSources[key]; } - const pref = new UIEventSource(this.preferences[key]); + this.UpdatePreferences(); + console.log("Getting preference object", key, "currently upstreamed as ",this.preferences.data[key] ); + const pref = new UIEventSource(this.preferences.data[key]); pref.addCallback((v) => { this.SetPreference(key, v); }); @@ -187,7 +189,7 @@ export class OsmConnection { return; } - console.log("Preference written!", result); + console.log("Preference written!", result == "" ? "OK" : result); }); } diff --git a/assets/Buurtnatuur-Welkom.txt b/assets/Buurtnatuur-Welkom.txt new file mode 100644 index 0000000..febd369 --- /dev/null +++ b/assets/Buurtnatuur-Welkom.txt @@ -0,0 +1,20 @@ +Hallo, + +Je maakte een bijdrage aan OpenStreetMap met BuurtNatuur! Proficiat en welkom bij de community. + +Je antwoorden en toevoegingen gaan rechtsstreeks naar OpenStreetMap. OpenStreetMap is een kaart die werkt zoals Wikipedia: +het is vrij en gratis om er zelf data aan toe te voegen; in het geval van buurtnatuur.be informatie over natuur en bossen. +De data van OpenStreetMap is ook vrij en gratis te gebruiken door iedereen die dit wilt - applicaties zoals Maps.me, OsmAnd, Pokemon Go, Facebook, SnapChat, RouteYou, de Natuurpunt-app,... gebruiken OpenStreetMap. Maar ook toeristische diensten (zoals Westtoer) gebruiken steeds vaker OpenStreetMap. + +Kortom, omdat je via buurtnatuur.be info gaf over natuur en bos, wordt dit zichtbaar op ál deze kaarten. + +Heb je verdere vragen over OpenStreetMap? Wil je weten welke data we allemaal hebben en verzamelen? + +- Je kan meer lezen op [onze wiki-website](https://wiki.openstreetmap.org/wiki/NL:Hoofdpagina). +- Je kan mij een berichtje terug sturen (dit kan door een email terug te sturen) +- Je kan terecht op [online chat](https://riot.im/app/#/room/#osmbe:matrix.org) +- Je kan naar onze [bijeenkomsten komen](https://www.meetup.com/OpenStreetMap-Belgium/) + +Happy Mapping! +Pieter Vander Vennet +OpenStreetMap België From 58bcdbe17ae5a43eeca1fe134a83093fe739b238 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 15 Jul 2020 11:23:35 +0200 Subject: [PATCH 6/8] Adding documentation --- Customizations/LayerDefinition.ts | 26 ++++++++++++++++++++++++++ Customizations/Layout.ts | 19 ++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Customizations/LayerDefinition.ts b/Customizations/LayerDefinition.ts index 03822e3..14f9b40 100644 --- a/Customizations/LayerDefinition.ts +++ b/Customizations/LayerDefinition.ts @@ -16,9 +16,35 @@ export class LayerDefinition { * This name is shown in the 'add XXX button' */ name: string; + /** + * These tags are added whenever a new point is added by the user on the map. + * This is the ideal place to add extra info, such as "fixme=added by MapComplete, geometry should be checked" + */ newElementTags: Tag[] + /** + * Not really used anymore + * This is meant to serve as icon in the buttons + */ icon: string; + /** + * Only show this layer starting at this zoom level + */ minzoom: number; + + /** + * This tagfilter is used to query overpass. + * Examples are: + * + * new Tag("amenity","drinking_water") + * + * or a query for bicycle pumps which have two tagging schemes: + * new Or([ + * new Tag("service:bicycle:pump","yes") , + * new And([ + * new Tag("amenity","compressed_air"), + * new Tag("bicycle","yes")]) + * ]) + */ overpassFilter: TagsFilter; /** diff --git a/Customizations/Layout.ts b/Customizations/Layout.ts index 7a5b880..7c72927 100644 --- a/Customizations/Layout.ts +++ b/Customizations/Layout.ts @@ -17,7 +17,20 @@ export class Layout { public welcomeTail: string; public locationContains: string[]; - + + /** + * + * @param name: The name used in the query string. If in the query "quests=" is defined, it will select this layout + * @param title: Will be used in the of the page + * @param layers: The layers to show, a list of LayerDefinitions + * @param startzoom: The initial starting zoom of the map + * @param startLat:The initial starting latitude of the map + * @param startLon: the initial starting longitude of the map + * @param welcomeMessage: This message is shown in the collapsable box on the left + * @param gettingStartedPlzLogin: This is shown below the welcomemessage and wrapped in a login link. + * @param welcomeBackMessage: This is shown when the user is logged in + * @param welcomeTail: This text is shown below the login message. It is ideal for extra help + */ constructor( name: string, title: string, @@ -26,8 +39,8 @@ export class Layout { startLat: number, startLon: number, welcomeMessage: string, - gettingStartedPlzLogin: string, - welcomeBackMessage: string, + gettingStartedPlzLogin: string = "Please login to get started", + welcomeBackMessage: string = "You are logged in. Welcome back!", welcomeTail: string = "" ) { this.title = title; From 9e43be6a07778b1b5e74d2b3a9872132509b8e47 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@gmail.com> Date: Wed, 15 Jul 2020 13:15:36 +0200 Subject: [PATCH 7/8] Documentation --- Customizations/TagRendering.ts | 49 ++++++++++++++++++--------- UI/SimpleAddUI.ts | 8 ++--- index.html | 4 +-- index.ts | 61 ++++++++++++++++++---------------- test.ts | 8 +++++ 5 files changed, 79 insertions(+), 51 deletions(-) diff --git a/Customizations/TagRendering.ts b/Customizations/TagRendering.ts index a02f2a0..c5f8d63 100644 --- a/Customizations/TagRendering.ts +++ b/Customizations/TagRendering.ts @@ -27,11 +27,7 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor { constructor(options: { - /** - * What is the priority of the question. - * By default, in the popup of a feature, only one question is shown at the same time. If multiple questions are unanswered, the question with the highest priority is asked first - */ - priority?: number + /** * This is the string that is shown in the popup if this tag is missing. @@ -42,17 +38,12 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor { question?: string, /** - * Optional: - * if defined, this a common piece of tag that is shown in front of every mapping (except freeform) + * What is the priority of the question. + * By default, in the popup of a feature, only one question is shown at the same time. If multiple questions are unanswered, the question with the highest priority is asked first */ - primer?: string, - tagsPreprocessor?: ((tags: any) => any), - freeform?: { - key: string, template: string, - renderTemplate: string - placeholder?: string, - extraTags?: TagsFilter, - }, + priority?: number, + + /** * Mappings convert a well-known tag combination into a user friendly text. * It converts e.g. 'access=yes' into 'this area can be accessed' @@ -65,7 +56,33 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor { * * */ - mappings?: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[] + mappings?: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[], + + + /** + * If one wants to render a freeform tag (thus no predefined key/values) or if there are a few well-known tags with a freeform object, + * use this. + * In the question, it'll offer a textfield + */ + freeform?: { + key: string, template: string, + renderTemplate: string + placeholder?: string, + extraTags?: TagsFilter, + }, + + + /** + * Optional: + * if defined, this a common piece of tag that is shown in front of every mapping (except freeform) + */ + primer?: string, + + /** + * In some very rare cases, tags have to be rewritten before displaying + * This function adds this + */ + tagsPreprocessor?: ((tags: any) => any) }) { this.options = options; } diff --git a/UI/SimpleAddUI.ts b/UI/SimpleAddUI.ts index 4deb4b3..b235437 100644 --- a/UI/SimpleAddUI.ts +++ b/UI/SimpleAddUI.ts @@ -63,6 +63,10 @@ export class SimpleAddUI extends UIElement { protected InnerRender(): string { const header = "<h2>Geen selectie</h2>" + "Je klikte ergens waar er nog geen gezochte data is.<br/>"; + if (!this._userDetails.data.loggedIn) { + return header + "<a class='activate-osm-authentication'>Gelieve je aan te melden om een nieuw punt toe te voegen</a>" + } + if (this._zoomlevel.data.zoom < 19) { return header + "Zoom verder in om een element toe te voegen."; } @@ -71,10 +75,6 @@ export class SimpleAddUI extends UIElement { return header + "De data is nog aan het laden. Nog even geduld, dan kan je een punt toevoegen"; } - if (!this._userDetails.data.loggedIn) { - return header + "<a class='activate-osm-authentication'>Gelieve je aan te melden om een nieuw punt toe te voegen</a>" - } - var html = ""; for (const button of this._addButtons) { html += button.Render(); diff --git a/index.html b/index.html index 16c5387..a6fdedd 100644 --- a/index.html +++ b/index.html @@ -23,10 +23,10 @@ </div> <div id="topleft-tools"> - <div id="userbadge-and-search"> - <div id="userbadge"> Loading... If this message persists, check if javascript is enabled and if no extension (uMatrix) is blocking it. + <div id="userbadge-and-search"> + <div id="userbadge"> </div> <br/> <div id="searchbox"></div> diff --git a/index.ts b/index.ts index 73b8cea..6b9cd82 100644 --- a/index.ts +++ b/index.ts @@ -50,43 +50,47 @@ if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { // ----------------- SELECT THE RIGHT QUESTSET ----------------- -let defaultQuest = "buurtnatuur" +let defaultLayout = "buurtnatuur" + +// 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 possibleParts = layout.locationContains ?? []; - console.log(layout.locationContains) for (const locationMatch of possibleParts) { - if(locationMatch === ""){ + if (locationMatch === "") { continue } - console.log(layout.name," -> ", locationMatch, window.location.href.indexOf(locationMatch)) - if(window.location.href.toLowerCase().indexOf(locationMatch.toLowerCase()) >= 0){ - defaultQuest = layout.name; - console.log("Detected a default by URL: ", layout.name, "matches", locationMatch) + if (window.location.href.toLowerCase().indexOf(locationMatch.toLowerCase()) >= 0) { + defaultLayout = layout.name; } } } +// Read the query string to grap settings +let paramDict: any = {}; if (window.location.search) { const params = window.location.search.substr(1).split("&"); - const paramDict: any = {}; for (const param of params) { var kv = param.split("="); paramDict[kv[0]] = kv[1]; } - if (paramDict.quests) { - defaultQuest = paramDict.quests - } - if(paramDict.test){ - dryRun = true; - } + + } -const questSetToRender = AllKnownLayouts.allSets[defaultQuest]; -console.log("Using quests: ", questSetToRender.name); +if (paramDict.layout) { + defaultLayout = paramDict.quests +} -document.title = questSetToRender.title; +if (paramDict.test) { + dryRun = true; +} + +const layoutToUse = AllKnownLayouts.allSets[defaultLayout]; +console.log("Using layout: ", layoutToUse.name); + +document.title = layoutToUse.title; // ----------------- Setup a few event sources ------------- @@ -104,9 +108,9 @@ const selectedElement = new UIEventSource<any>(undefined); const locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({ - zoom: questSetToRender.startzoom, - lat: questSetToRender.startLat, - lon: questSetToRender.startLon + zoom: layoutToUse.startzoom, + lat: layoutToUse.startLat, + lon: layoutToUse.startLon }); @@ -116,7 +120,7 @@ const saveTimeout = 30000; // After this many milliseconds without changes, save const allElements = new ElementStorage(); const osmConnection = new OsmConnection(dryRun); const changes = new Changes( - "Beantwoorden van vragen met #MapComplete voor vragenset #" + questSetToRender.name, + "Beantwoorden van vragen met #MapComplete voor vragenset #" + layoutToUse.name, osmConnection, allElements); const bm = new Basemap("leafletDiv", locationControl, new VariableUiElement( locationControl.map((location) => { @@ -150,7 +154,7 @@ const flayers: FilteredLayer[] = [] let minZoom = 0; -for (const layer of questSetToRender.layers) { +for (const layer of layoutToUse.layers) { const generateInfo = (tagsES) => { @@ -164,9 +168,8 @@ for (const layer of questSetToRender.layers) { }; minZoom = Math.max(minZoom, layer.minzoom); - - const flayer = layer.asLayer(bm, allElements, changes, osmConnection.userDetails, selectedElement, - generateInfo); + + const flayer = layer.asLayer(bm, allElements, changes, osmConnection.userDetails, selectedElement, generateInfo); const addButton = { name: layer.name, @@ -200,7 +203,7 @@ new StrayClickHandler(bm, selectedElement, leftMessage, () => { */ selectedElement.addCallback((data) => { // Which is the applicable set? - for (const layer of questSetToRender.layers) { + for (const layer of layoutToUse.layers) { const applicable = layer.overpassFilter.matches(TagUtils.proprtiesToKV(data)); if (applicable) { @@ -234,12 +237,12 @@ new CollapseButton("messagesbox") var welcomeMessage = () => { return new VariableUiElement( osmConnection.userDetails.map((userdetails) => { - var login = questSetToRender.gettingStartedPlzLogin; + var login = layoutToUse.gettingStartedPlzLogin; if (userdetails.loggedIn) { - login = questSetToRender.welcomeBackMessage; + login = layoutToUse.welcomeBackMessage; } return "<div id='welcomeMessage'>" + - questSetToRender.welcomeMessage + login + questSetToRender.welcomeTail+ + layoutToUse.welcomeMessage + login + layoutToUse.welcomeTail + "</div>"; }), function () { diff --git a/test.ts b/test.ts index d4b510f..b7e9bd3 100644 --- a/test.ts +++ b/test.ts @@ -6,4 +6,12 @@ import {WikipediaLink} from "./Customizations/Questions/WikipediaLink"; import {OsmLink} from "./Customizations/Questions/OsmLink"; import {ConfirmDialog} from "./UI/ConfirmDialog"; import {Imgur} from "./Logic/Imgur"; +import {VariableUiElement} from "./UI/Base/VariableUIElement"; + +const html = new UIEventSource<string>("Some text"); + +const uielement = new VariableUiElement(html); +uielement.AttachTo("maindiv") + +window.setTimeout(() => {html.setData("Different text")}, 1000) \ No newline at end of file From bb61f7777ff45b5edcfb3ad6c9001ed19ee4602d Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@gmail.com> Date: Thu, 16 Jul 2020 09:25:20 +0200 Subject: [PATCH 8/8] Bike pump updates --- Customizations/Layers/BikePumps.ts | 69 ++++++++++++++++++++++---- Customizations/Layers/GhostBike.ts | 33 ++++++++++++ Customizations/Questions/PumpManual.ts | 23 --------- index.html | 4 +- index.ts | 2 +- 5 files changed, 95 insertions(+), 36 deletions(-) delete mode 100644 Customizations/Questions/PumpManual.ts diff --git a/Customizations/Layers/BikePumps.ts b/Customizations/Layers/BikePumps.ts index d53f6d8..cae021b 100644 --- a/Customizations/Layers/BikePumps.ts +++ b/Customizations/Layers/BikePumps.ts @@ -1,10 +1,9 @@ import {LayerDefinition} from "../LayerDefinition"; import {And, Or, Tag} from "../../Logic/TagsFilter"; -import {OperatorTag} from "../Questions/OperatorTag"; import * as L from "leaflet"; -import { PumpManual } from "../Questions/PumpManual"; import FixedText from "../Questions/FixedText"; import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload"; +import {TagRenderingOptions} from "../TagRendering"; export class BikePumps extends LayerDefinition { @@ -14,12 +13,21 @@ export class BikePumps extends LayerDefinition { this.icon = "./assets/bike_pump.svg"; this.overpassFilter = - new And([ - new Tag("amenity", "bicycle_repair_station"), - new Tag("service:bicycle:pump", "yes"), + new Or([ + new And([ + new Tag("amenity", "compressed_air"), + new Tag("bicycle", "yes") + ]), + new And([ + new Tag("amenity", "bicycle_repair_station"), + new Tag("service:bicycle:pump", "yes"), + /* new Or([ + new Tag("service:bicycle:tools", ""), + new Tag("service:bicycle:tools", "no"), + ])*/ + ]), ]); - this.newElementTags = [ new Tag("amenity", "bicycle_repair_station"), new Tag("service:bicycle:pump", "yes"), @@ -44,10 +52,51 @@ export class BikePumps extends LayerDefinition { this.title = new FixedText("Pomp"); this.elementsToShow = [ new ImageCarouselWithUploadConstructor(), - // new NameQuestion(), - // new AccessTag(), - new OperatorTag(), - new PumpManual() + + new TagRenderingOptions({ + question: "What valves are supported?", + mappings: [ + { + k: new Tag("valves", " sclaverand;schrader;dunlop"), + txt: "There is a default head, so Presta, Dunlop and Auto" + }, + {k: new Tag("valves", "dunlop"), txt: "Only dunlop"}, + {k: new Tag("valves", "sclaverand"), txt: "Only Sclaverand (also known as Dunlop)"}, + {k: new Tag("valves", "auto"), txt: "Only auto"}, + ], + freeform: { + key: "valves", + template: "Supported valves are $$$", + renderTemplate: "Supported valves are {valves}" + } + }), + + new TagRenderingOptions({ + question: "Who maintains this bicycle pump?", + freeform: { + key: "operator", + template: "Maintained by $$$", + renderTemplate: "Maintained by {operator}", + placeholder: "operator" + } + }), + + new TagRenderingOptions({ + question: "Does the pump have a pressure indicator or manometer?", + mappings: [ + {k: new Tag("manometer", "yes"), txt: "Yes, there is a manometer"}, + {k: new Tag("manometer", "yes"), txt: "No"} + ] + + }), + + /* new TagRenderingOptions({ + question: "Is dit een manuele pomp?", + mappings: [ + {k: new Tag("manual", "yes"), txt: "Manuele pomp"}, + {k: new Tag("manual", "no"), txt: "Automatische pomp"} + ] + }) */ ]; } diff --git a/Customizations/Layers/GhostBike.ts b/Customizations/Layers/GhostBike.ts index f88d274..83a4455 100644 --- a/Customizations/Layers/GhostBike.ts +++ b/Customizations/Layers/GhostBike.ts @@ -18,6 +18,39 @@ export class GhostBike extends LayerDefinition { " in the form of a white bicycle placed permanently near the accident location."), new ImageCarouselWithUploadConstructor(), + new TagRenderingOptions({ + question: "Whom is remembered by this ghost bike?" + + "<span class='question-subtext'>" + + "<br/>" + + "Please respect privacy - only fill out the name if it is widely published or marked on the cycle." + + "</span>", + mappings: [{k: new Tag("noname", "yes"), txt: "There is no name marked on the bike"},], + freeform: { + key: "name", + extraTags: new Tag("noname", ""), + template: "$$$", + renderTemplate: "In the remembrance of <b>{name}</b>", + } + }), + new TagRenderingOptions({ + question: "When was the ghost bike installed?", + freeform: { + key: "start_date", + template: "The ghost bike was placed on $$$", // TODO create a date picker + renderTemplate: "The ghost bike was placed on <b>{start_date}</b>", + } + }), + new TagRenderingOptions({ + question: "On what URL can more information be found?" + + "<span class='question-subtext'>If available, add a link to a news report about the accident or about the placing of the ghost bike</span>", + freeform: { + key: "source", + template: "More information available on $$$", + renderTemplate: "<a href='{source}' target='_blank'>More information</a>", + } + }), + + ]; diff --git a/Customizations/Questions/PumpManual.ts b/Customizations/Questions/PumpManual.ts deleted file mode 100644 index cfb8356..0000000 --- a/Customizations/Questions/PumpManual.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {TagRenderingOptions} from "../TagRendering"; -import {UIEventSource} from "../../UI/UIEventSource"; -import {Changes} from "../../Logic/Changes"; -import {Tag} from "../../Logic/TagsFilter"; - - -export class PumpManual extends TagRenderingOptions { - - - private static options = { - priority: 5, - question: "Is dit een manuele pomp?", - mappings: [ - {k: new Tag("manual", "yes"), txt: "Manuele pomp"}, - {k: new Tag("manual", "no"), txt: "Automatische pomp"} - ] - } - - constructor() { - super(PumpManual.options); - } - -} \ No newline at end of file diff --git a/index.html b/index.html index a6fdedd..16c5387 100644 --- a/index.html +++ b/index.html @@ -23,10 +23,10 @@ </div> <div id="topleft-tools"> - Loading... If this message persists, check if javascript is enabled and if no extension (uMatrix) is - blocking it. <div id="userbadge-and-search"> <div id="userbadge"> + Loading... If this message persists, check if javascript is enabled and if no extension (uMatrix) is + blocking it. </div> <br/> <div id="searchbox"></div> diff --git a/index.ts b/index.ts index 6b9cd82..6696d39 100644 --- a/index.ts +++ b/index.ts @@ -80,7 +80,7 @@ if (window.location.search) { } if (paramDict.layout) { - defaultLayout = paramDict.quests + defaultLayout = paramDict.layout } if (paramDict.test) {