diff --git a/Customizations/AllKnownLayouts.ts b/Customizations/AllKnownLayouts.ts
index 8fea419..c3008f8 100644
--- a/Customizations/AllKnownLayouts.ts
+++ b/Customizations/AllKnownLayouts.ts
@@ -3,8 +3,7 @@ import {Toilets} from "./Layouts/Toilets";
import {GRB} from "./Layouts/GRB";
import {Statues} from "./Layouts/Statues";
import {Bookcases} from "./Layouts/Bookcases";
-import { BikePumps } from "./Layers/BikePumps";
-import { BikePumpsLayout } from "./Layouts/BikePumps";
+import Cyclofix from "./Layouts/Cyclofix";
export class AllKnownLayouts {
public static allSets: any = AllKnownLayouts.AllLayouts();
@@ -13,10 +12,11 @@ export class AllKnownLayouts {
const layouts = [
new Groen(),
new GRB(),
- new BikePumpsLayout(),
+ new Cyclofix(),
+ new Bookcases()
/*new Toilets(),
new Statues(),
- new Bookcases()*/
+ */
];
const allSets = {};
for (const layout of layouts) {
diff --git a/Customizations/LayerDefinition.ts b/Customizations/LayerDefinition.ts
index bd64aa4..945f299 100644
--- a/Customizations/LayerDefinition.ts
+++ b/Customizations/LayerDefinition.ts
@@ -11,13 +11,22 @@ import {TagRenderingOptions} from "./TagRendering";
export class LayerDefinition {
+ /**
+ * This name is shown in the 'add XXX button'
+ */
name: string;
newElementTags: Tag[]
icon: string;
minzoom: number;
overpassFilter: TagsFilter;
+ /**
+ * This UIElement is rendered as title element in the popup
+ */
title: TagRenderingOptions;
+ /**
+ * These are the questions/shown attributes in the popup
+ */
elementsToShow: TagRenderingOptions[];
style: (tags: any) => { color: string, icon: any };
diff --git a/Customizations/Layers/Bookcases.ts b/Customizations/Layers/Bookcases.ts
index 81015f1..fcd621c 100644
--- a/Customizations/Layers/Bookcases.ts
+++ b/Customizations/Layers/Bookcases.ts
@@ -3,6 +3,7 @@ import L from "leaflet";
import {Tag} from "../../Logic/TagsFilter";
import {QuestionDefinition} from "../../Logic/Question";
import {TagRenderingOptions} from "../TagRendering";
+import {NameInline} from "../Questions/NameInline";
export class Bookcases extends LayerDefinition {
@@ -10,21 +11,38 @@ export class Bookcases extends LayerDefinition {
super();
this.name = "boekenkast";
- this.newElementTags = [new Tag( "amenity", "public_bookcase")];
+ this.newElementTags = [new Tag("amenity", "public_bookcase")];
this.icon = "./assets/bookcase.svg";
- this.overpassFilter = new Tag("amenity","public_bookcase");
+ this.overpassFilter = new Tag("amenity", "public_bookcase");
this.minzoom = 13;
+ this.title = new NameInline("ruilboekenkastje");
+ this.elementsToShow = [
- this.questions = [
+ new TagRenderingOptions(
+ {
+ question: "Hoeveel boeken passen in dit boekenruilkastje?",
+ freeform: {
+ renderTemplate: "Er passen {capacity} boeken in dit boekenruilkastje",
+ template: "Er passen $$$ boeken in dit boekenruilkastje",
+ key: "capacity",
+ placeholder: "aantal"
+ },
+ priority: 15
+ }
+ )
+
+ ];
+
+ /* this.questions = [
QuestionDefinition.noNameOrNameQuestion("Wat is de naam van dit boekenruilkastje?", "Dit boekenruilkastje heeft niet echt een naam", 20),
- QuestionDefinition.textQuestion("Hoeveel boeken kunnen er in?", "capacity", 15),
QuestionDefinition.textQuestion("Heeft dit boekenkastje een peter, meter of voogd?", "operator", 10),
- // QuestionDefinition.textQuestion("Wie kunnen we (per email) contacteren voor dit boekenruilkastje?", "email", 5),
+ // QuestionDefinition.textQuestion("Wie kunnen we (per email) contacteren voor dit boekenruilkastje?", "email", 5),
- ]
+ ]
;
+ */
this.style = function (tags) {
return {
@@ -36,6 +54,7 @@ export class Bookcases extends LayerDefinition {
};
}
+ /*
this.elementsToShow = [
@@ -58,7 +77,7 @@ export class Bookcases extends LayerDefinition {
new TagMappingOptions({key: "description", template: "Extra beschrijving:
{description}
"}),
]
- ;
+ ;*/
}
diff --git a/Customizations/Layers/Park.ts b/Customizations/Layers/Park.ts
index 3736435..dcce5d1 100644
--- a/Customizations/Layers/Park.ts
+++ b/Customizations/Layers/Park.ts
@@ -9,6 +9,32 @@ import {NameInline} from "../Questions/NameInline";
export class Park extends LayerDefinition {
+
+ private accessByDefault = new TagRenderingOptions({
+ question: "Is dit park publiek toegankelijk?",
+ mappings: [
+ {k: new Tag("access", "yes"), txt: "Publiek toegankelijk"},
+ {k: new Tag("access", ""), txt: "Publiek toegankelijk"},
+ {k: new Tag("access", "no"), txt: "Niet publiek toegankelijk"},
+ {k: new Tag("access", "guided"), txt: "Enkel toegankelijk met een gids of op een activiteit"}
+ ]
+ })
+
+ private operatorByDefault = new
+
+ TagRenderingOptions({
+ question: "Wie beheert dit park?",
+ freeform: {
+ key: "operator",
+ renderTemplate: "Dit park wordt beheerd door {operator}",
+ template: "$$$",
+ },
+ mappings: [{
+ k: null, txt: "De gemeente beheert dit park"
+ }]
+ });
+
+
constructor() {
super();
this.name = "park";
@@ -22,7 +48,11 @@ export class Park extends LayerDefinition {
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new NameInline("park");
- this.elementsToShow = [new NameQuestion()];
+ this.elementsToShow = [new NameQuestion(),
+ this.accessByDefault,
+ this.operatorByDefault
+
+ ];
}
diff --git a/Customizations/Layouts/Cyclofix.ts b/Customizations/Layouts/Cyclofix.ts
index 26adde7..7ba29ad 100644
--- a/Customizations/Layouts/Cyclofix.ts
+++ b/Customizations/Layouts/Cyclofix.ts
@@ -3,7 +3,7 @@ import {GrbToFix} from "../Layers/GrbToFix";
import { BikePumps } from "../Layers/BikePumps";
import { BikeParkings } from "../Layers/BikeParkings";
-export class BikePumpsLayout extends Layout {
+export default class Cyclofix extends Layout {
constructor() {
super(
"pomp",
@@ -14,10 +14,14 @@ export class BikePumpsLayout extends Layout {
3.2279,
- "
GRB Fix tool
\n" +
+ "
Cyclofix bicycle infrastructure
\n" +
"\n" +
- "Expert use only"
-
+ "
EN> On this map we want to collect data about the whereabouts of bicycle pumps and public racks in Brussels." +
+ "As a result, cyclists will be able to quickly find the nearest infrastructure for their needs.
" +
+ "
NL> Op deze kaart willen we gegevens verzamelen over de locatie van fietspompen en openbare stelplaatsen in Brussel." +
+ "Hierdoor kunnen fietsers snel de dichtstbijzijnde infrastructuur vinden die voldoet aan hun behoeften.
" +
+ "
FR> Sur cette carte, nous voulons collecter des données sur la localisation des pompes à vélo et des supports publics à Bruxelles." +
+ "Les cyclistes pourront ainsi trouver rapidement l'infrastructure la plus proche de leurs besoins.
"
,
"", "");
}
diff --git a/Customizations/Layouts/Groen.ts b/Customizations/Layouts/Groen.ts
index 2432869..f27da74 100644
--- a/Customizations/Layouts/Groen.ts
+++ b/Customizations/Layouts/Groen.ts
@@ -6,7 +6,7 @@ import {Layout} from "../Layout";
export class Groen extends Layout {
constructor() {
- super("groen",
+ super("buurtnatuur",
"Buurtnatuur",
[new NatureReserves(), new Park(), new Bos()],
10,
diff --git a/Customizations/TagRendering.ts b/Customizations/TagRendering.ts
index 2158baa..d299e9d 100644
--- a/Customizations/TagRendering.ts
+++ b/Customizations/TagRendering.ts
@@ -23,9 +23,25 @@ export class TagRenderingOptions {
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.
+ *
+ * If 'question' is undefined, then the question is never asked at all
+ * If the question is "" (empty string) then the question is
+ */
question?: string,
+
+ /**
+ * Optional:
+ * if defined, this a common piece of tag that is shown in front of every mapping (except freeform)
+ */
primer?: string,
tagsPreprocessor?: ((tags: any) => any),
freeform?: {
@@ -34,10 +50,21 @@ export class TagRenderingOptions {
placeholder?: string,
extraTags?: TagsFilter,
},
+ /**
+ * Mappings convert a well-known tag combination into a user friendly text.
+ * It converts e.g. 'access=yes' into 'this area can be accessed'
+ *
+ * If there are multiple tags that should be matched, And can be used. All tags in AND will be added when the question is picked (and the corresponding text will only be shown if all tags are present).
+ * If AND is used, it is best practice to make sure every used tag is in every option (with empty string) to erase extra tags.
+ *
+ * If a 'k' is null, then this one is shown by default. It can be used to force a default value, e.g. to show that the name of a POI is not (yet) known .
+ * A mapping where 'k' is null will not be shown as option in the radio buttons.
+ *
+ *
+ */
mappings?: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[]
}) {
this.options = options;
-
}
@@ -45,7 +72,7 @@ export class TagRenderingOptions {
const tagsKV = TagUtils.proprtiesToKV(tags);
for (const oneOnOneElement of this.options.mappings) {
- if (oneOnOneElement.k.matches(tagsKV)) {
+ if (oneOnOneElement.k === null || oneOnOneElement.k.matches(tagsKV)) {
return false;
}
}
@@ -71,6 +98,8 @@ export class TagRendering extends UIElement {
private _question: string;
private _primer: string;
private _mapping: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[];
+ private _renderMapping: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[];
+
private _tagsPreprocessor?: ((tags: any) => any);
private _freeform: {
key: string, template: string,
@@ -116,13 +145,14 @@ export class TagRendering extends UIElement {
this._primer = options.primer ?? "";
this._tagsPreprocessor = options.tagsPreprocessor;
this._mapping = [];
+ this._renderMapping = [];
this._freeform = options.freeform;
this.elementPriority = options.priority ?? 0;
// Prepare the choices for the Radio buttons
- let i = 0;
const choices: UIElement[] = [];
-
+ const usedChoices: string [] = [];
+
for (const choice of options.mappings ?? []) {
if (choice.k === null) {
this._mapping.push(choice);
@@ -131,18 +161,26 @@ export class TagRendering extends UIElement {
let choiceSubbed = choice;
if (choice.substitute) {
choiceSubbed = {
- k : choice.k.substituteValues(
+ k: choice.k.substituteValues(
options.tagsPreprocessor(this._source.data)),
- txt : this.ApplyTemplate(choice.txt),
+ txt: this.ApplyTemplate(choice.txt),
substitute: false,
priority: choice.priority
}
}
-
- choices.push(new FixedUiElement(choiceSubbed.txt));
- this._mapping.push(choiceSubbed);
- i++;
+
+ const txt = choiceSubbed.txt
+ // Choices is what is shown in the radio buttons
+ if (usedChoices.indexOf(txt) < 0) {
+
+ choices.push(new FixedUiElement(txt));
+ usedChoices.push(txt);
+ // This is used to convert the radio button index into tags needed to add
+ this._mapping.push(choiceSubbed);
+ } else {
+ this._renderMapping.push(choiceSubbed); // only used while rendering
+ }
}
// Map radiobutton choice and textfield answer onto tagfilter. That tagfilter will be pushed into the changes later on
@@ -172,6 +210,7 @@ export class TagRendering extends UIElement {
// Prepare the actual input element -> pick an appropriate implementation
let inputElement: UIInputElement;
+
if (this._freeform !== undefined && this._mapping !== undefined) {
// Radio buttons with 'other'
inputElement = new UIRadioButtonWithOther(
@@ -182,14 +221,15 @@ export class TagRendering extends UIElement {
pickString
);
this._questionElement = inputElement;
- } else if (this._mapping !== undefined) {
+ } else if (this._mapping !== [] && this._mapping.length > 0) {
// This is a classic radio selection element
- inputElement = new UIRadioButton(new UIEventSource(choices), pickChoice)
+ inputElement = new UIRadioButton(new UIEventSource(choices), pickChoice, false)
this._questionElement = inputElement;
} else if (this._freeform !== undefined) {
this._textField = new TextField(new UIEventSource(this._freeform.placeholder), pickString);
inputElement = this._textField;
- this._questionElement = new FixedUiElement(this._freeform.template.replace("$$$", inputElement.Render()))
+ this._questionElement = new FixedUiElement(
+ "