Better bookcase quests
This commit is contained in:
parent
1ef2459d54
commit
49cab66a72
11 changed files with 247 additions and 63 deletions
|
@ -4,16 +4,19 @@ import {GRB} from "./Layouts/GRB";
|
|||
import {Statues} from "./Layouts/Statues";
|
||||
import {Bookcases} from "./Layouts/Bookcases";
|
||||
import Cyclofix from "./Layouts/Cyclofix";
|
||||
import {All} from "./Layouts/All";
|
||||
|
||||
export class AllKnownLayouts {
|
||||
public static allSets: any = AllKnownLayouts.AllLayouts();
|
||||
|
||||
private static AllLayouts() {
|
||||
const all = new All();
|
||||
const layouts = [
|
||||
new Groen(),
|
||||
new GRB(),
|
||||
new Cyclofix(),
|
||||
new Bookcases()
|
||||
new Bookcases(),
|
||||
all
|
||||
/*new Toilets(),
|
||||
new Statues(),
|
||||
*/
|
||||
|
@ -21,6 +24,7 @@ export class AllKnownLayouts {
|
|||
const allSets = {};
|
||||
for (const layout of layouts) {
|
||||
allSets[layout.name] = layout;
|
||||
all.layers = all.layers.concat(layout.layers);
|
||||
}
|
||||
return allSets;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {FilteredLayer} from "../Logic/FilteredLayer";
|
|||
import {Changes} from "../Logic/Changes";
|
||||
import {UserDetails} from "../Logic/OsmConnection";
|
||||
import {TagRenderingOptions} from "./TagRendering";
|
||||
import {TagDependantUIElementConstructor} from "./UIElementConstructor";
|
||||
|
||||
export class LayerDefinition {
|
||||
|
||||
|
@ -27,7 +28,7 @@ export class LayerDefinition {
|
|||
/**
|
||||
* These are the questions/shown attributes in the popup
|
||||
*/
|
||||
elementsToShow: TagRenderingOptions[];
|
||||
elementsToShow: TagDependantUIElementConstructor[];
|
||||
|
||||
style: (tags: any) => { color: string, icon: any };
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {LayerDefinition} from "../LayerDefinition";
|
||||
import L from "leaflet";
|
||||
import {Tag} from "../../Logic/TagsFilter";
|
||||
import {And, Regex, Tag} from "../../Logic/TagsFilter";
|
||||
import {QuestionDefinition} from "../../Logic/Question";
|
||||
import {TagRenderingOptions} from "../TagRendering";
|
||||
import {NameInline} from "../Questions/NameInline";
|
||||
|
@ -21,7 +21,6 @@ export class Bookcases extends LayerDefinition {
|
|||
this.elementsToShow = [
|
||||
|
||||
new TagRenderingOptions({
|
||||
priority: 13,
|
||||
question: "Heeft dit boekenruilkastje een naam?",
|
||||
freeform: {
|
||||
key: "name",
|
||||
|
@ -44,22 +43,88 @@ export class Bookcases extends LayerDefinition {
|
|||
key: "capacity",
|
||||
placeholder: "aantal"
|
||||
},
|
||||
priority: 15
|
||||
}
|
||||
),
|
||||
new TagRenderingOptions({
|
||||
question: "Wat voor soort boeken heeft dit boekenruilkastje?",
|
||||
mappings:[
|
||||
{k: new Tag("books","children"), txt: "Voornamelijk kinderboeken"},
|
||||
{k: new Tag("books","adults"), txt: "Voornamelijk boeken voor volwassenen"},
|
||||
{k: new Tag("books","children;adults"), txt: "Zowel kinderboeken als boeken voor volwassenen"}
|
||||
mappings: [
|
||||
{k: new Tag("books", "children"), txt: "Voornamelijk kinderboeken"},
|
||||
{k: new Tag("books", "adults"), txt: "Voornamelijk boeken voor volwassenen"},
|
||||
{k: new Tag("books", "children;adults"), txt: "Zowel kinderboeken als boeken voor volwassenen"}
|
||||
],
|
||||
priority: 14
|
||||
}),
|
||||
|
||||
new TagRenderingOptions({
|
||||
question: "",
|
||||
freeform:{
|
||||
question: "Staat dit boekenruilkastje binnen of buiten?",
|
||||
mappings: [
|
||||
{k: new Tag("indoor", "yes"), txt: "Dit boekenruilkastje staat binnen"},
|
||||
{k: new Tag("indoor", "no"), txt: "Dit boekenruilkastje staat buiten"},
|
||||
{k: new Tag("indoor", ""), txt: "Dit boekenruilkastje staat buiten"}
|
||||
]
|
||||
}),
|
||||
|
||||
new TagRenderingOptions({
|
||||
question: "Is dit boekenruilkastje vrij toegankelijk?",
|
||||
mappings: [
|
||||
{k: new Tag("access", "yes"), txt: "Ja, vrij toegankelijk"},
|
||||
{k: new Tag("access", "customers"), txt: "Enkel voor klanten"},
|
||||
]
|
||||
}).OnlyShowIf(new Tag("indoor", "yes")),
|
||||
new TagRenderingOptions({
|
||||
question: "Wie (welke organisatie) beheert dit boekenruilkastje?",
|
||||
freeform: {
|
||||
key: "opeartor",
|
||||
renderTemplate: "Dit boekenruilkastje wordt beheerd door {operator}",
|
||||
template: "Dit boekenruilkastje wordt beheerd door $$$"
|
||||
}
|
||||
}),
|
||||
|
||||
new TagRenderingOptions({
|
||||
question: "Zijn er openingsuren voor dit boekenruilkastje?",
|
||||
mappings: [
|
||||
{k: new Tag("opening_hours", "24/7"), txt: "Dag en nacht toegankelijk"},
|
||||
{k: new Tag("opening_hours", ""), txt: "Dag en nacht toegankelijk"},
|
||||
{k: new Tag("opening_hours", "sunrise-sunset"), txt: "Van zonsopgang tot zonsondergang"},
|
||||
],
|
||||
freeform: {
|
||||
key: "opening_hours",
|
||||
renderTemplate: "De openingsuren zijn {opening_hours}",
|
||||
template: "De openingsuren zijn $$$"
|
||||
}
|
||||
}),
|
||||
|
||||
new TagRenderingOptions({
|
||||
question: "Is dit boekenruilkastje deel van een netwerk?",
|
||||
freeform: {
|
||||
key: "brand",
|
||||
renderTemplate: "Deel van het netwerk {brand}",
|
||||
template: "Deel van het netwerk $$$"
|
||||
},
|
||||
mappings: [{
|
||||
k: new And([new Tag("brand", "Little Free Library"), new Tag("nobrand", "")]),
|
||||
txt: "Little Free Library"
|
||||
},
|
||||
{
|
||||
k: new And([new Tag("brand", ""), new Tag("nobrand", "yes")]),
|
||||
txt: "Maakt geen deel uit van een groter netwerk"
|
||||
}]
|
||||
}).OnlyShowIf(new And(
|
||||
[new Tag("brand", "!(Little Free Library)"),
|
||||
new Tag("ref", "")])),
|
||||
|
||||
new TagRenderingOptions({
|
||||
question: "Wat is het LFL-referentienummer van dit boekenruilkastje?",
|
||||
freeform: {
|
||||
key: "ref",
|
||||
template: "Het refernetienummer is $$$",
|
||||
renderTemplate: "Gekend als Little Free Library <b>{ref}</b>"
|
||||
}
|
||||
}).OnlyShowIf(new Tag("brand", "Little Free Library")),
|
||||
|
||||
new TagRenderingOptions({
|
||||
question: "Wanneer werd dit boekenruilkastje geinstalleerd?",
|
||||
priority: -1,
|
||||
freeform: {
|
||||
key: "start_date",
|
||||
renderTemplate: "Geplaatst op {start_date}",
|
||||
template: "Geplaatst op $$$"
|
||||
|
@ -68,42 +133,24 @@ export class Bookcases extends LayerDefinition {
|
|||
|
||||
new TagRenderingOptions({
|
||||
question: "Is er een website waar we er meer informatie is over dit boekenruilkastje?",
|
||||
freeform:{
|
||||
key:"website",
|
||||
freeform: {
|
||||
key: "website",
|
||||
renderTemplate: "<a href='{website}' target='_blank'>Meer informatie over dit boekenruilkastje</a>",
|
||||
template: "$$$",
|
||||
placeholder:"website"
|
||||
|
||||
},
|
||||
priority: 5
|
||||
placeholder: "website"
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
new TagRenderingOptions({
|
||||
freeform: {
|
||||
key: "description",
|
||||
renderTemplate: "<b>Beschrijving door de uitbater</b><br>{description}",
|
||||
template: "$$$",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
];
|
||||
|
||||
/*
|
||||
this.elementsToShow = [
|
||||
|
||||
|
||||
|
||||
new TagMappingOptions({key: "operator", template: "Onder de hoede van {operator}"}),
|
||||
new TagMappingOptions({key: "brand", template: "Deel van het netwerk {brand}"}),
|
||||
new TagMappingOptions({key: "ref", template: "Referentienummer {ref}"}),
|
||||
|
||||
new TagMappingOptions({key: "description", template: "Extra beschrijving: <br /> <p>{description}</p>"}),
|
||||
]
|
||||
;*/
|
||||
|
||||
/* this.questions = [
|
||||
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),
|
||||
|
||||
|
||||
]
|
||||
;
|
||||
*/
|
||||
|
||||
this.style = function (tags) {
|
||||
return {
|
||||
|
|
18
Customizations/Layouts/All.ts
Normal file
18
Customizations/Layouts/All.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import {Layout} from "../Layout";
|
||||
|
||||
export class All extends Layout{
|
||||
constructor() {
|
||||
super(
|
||||
"all",
|
||||
"All quest layers",
|
||||
[],
|
||||
15,
|
||||
51.2,
|
||||
3.2,
|
||||
"<h3>All quests of MapComplete</h3>" +
|
||||
"This is a mixed bag. Some quests might be hard or for experts to answer only",
|
||||
"Please log in",
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
79
Customizations/OnlyShowIf.ts
Normal file
79
Customizations/OnlyShowIf.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* Wrapper around another TagDependandElement, which only shows if the filters match
|
||||
*/
|
||||
import {TagDependantUIElement, TagDependantUIElementConstructor} from "./UIElementConstructor";
|
||||
import {TagsFilter, TagUtils} from "../Logic/TagsFilter";
|
||||
import {UIElement} from "../UI/UIElement";
|
||||
import {UIEventSource} from "../UI/UIEventSource";
|
||||
import {Changes} from "../Logic/Changes";
|
||||
|
||||
|
||||
export class OnlyShowIfConstructor implements TagDependantUIElementConstructor{
|
||||
private _tagsFilter: TagsFilter;
|
||||
private _embedded: TagDependantUIElementConstructor;
|
||||
|
||||
constructor(tagsFilter : TagsFilter, embedded: TagDependantUIElementConstructor) {
|
||||
this._tagsFilter = tagsFilter;
|
||||
this._embedded = embedded;
|
||||
}
|
||||
|
||||
construct(tags: UIEventSource<any>, changes: Changes): TagDependantUIElement {
|
||||
return new OnlyShowIf(tags,
|
||||
this._embedded.construct(tags, changes),
|
||||
this._tagsFilter);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class OnlyShowIf extends UIElement implements TagDependantUIElement {
|
||||
private _embedded: TagDependantUIElement;
|
||||
private _filter: TagsFilter;
|
||||
|
||||
constructor(
|
||||
tags: UIEventSource<any>,
|
||||
embedded: TagDependantUIElement, filter: TagsFilter) {
|
||||
super(tags);
|
||||
this._filter = filter;
|
||||
this._embedded = embedded;
|
||||
|
||||
}
|
||||
|
||||
private Matches() : boolean{
|
||||
return this._filter.matches(TagUtils.proprtiesToKV(this._source.data));
|
||||
}
|
||||
|
||||
protected InnerRender(): string {
|
||||
if (this.Matches()) {
|
||||
return this._embedded.Render();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Priority(): number {
|
||||
return this._embedded.Priority();
|
||||
}
|
||||
|
||||
IsKnown(): boolean {
|
||||
if(!this.Matches()){
|
||||
return false;
|
||||
}
|
||||
return this._embedded.IsKnown();
|
||||
}
|
||||
|
||||
IsQuestioning(): boolean {
|
||||
if(!this.Matches()){
|
||||
return false;
|
||||
}
|
||||
return this._embedded.IsQuestioning();
|
||||
}
|
||||
|
||||
Activate(): void {
|
||||
this._embedded.Activate();
|
||||
}
|
||||
|
||||
Update(): void {
|
||||
this._embedded.Update();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import {TagRendering, TagRenderingOptions} from "../TagRendering";
|
||||
import {TagRenderingOptions} from "../TagRendering";
|
||||
import {UIEventSource} from "../../UI/UIEventSource";
|
||||
import {Changes} from "../../Logic/Changes";
|
||||
import {And, Tag} from "../../Logic/TagsFilter";
|
||||
|
|
|
@ -9,8 +9,10 @@ import {TextField} from "../UI/Base/TextField";
|
|||
import {UIInputElement} from "../UI/Base/UIInputElement";
|
||||
import {UIRadioButtonWithOther} from "../UI/Base/UIRadioButtonWithOther";
|
||||
import {VariableUiElement} from "../UI/Base/VariableUIElement";
|
||||
import {TagDependantUIElement, TagDependantUIElementConstructor} from "./UIElementConstructor";
|
||||
import {OnlyShowIfConstructor} from "./OnlyShowIf";
|
||||
|
||||
export class TagRenderingOptions {
|
||||
export class TagRenderingOptions implements TagDependantUIElementConstructor {
|
||||
|
||||
/**
|
||||
* Notes: by not giving a 'question', one disables the question form alltogether
|
||||
|
@ -67,6 +69,10 @@ export class TagRenderingOptions {
|
|||
this.options = options;
|
||||
}
|
||||
|
||||
OnlyShowIf(tagsFilter: TagsFilter) : TagDependantUIElementConstructor{
|
||||
return new OnlyShowIfConstructor(tagsFilter, this);
|
||||
}
|
||||
|
||||
|
||||
IsQuestioning(tags: any): boolean {
|
||||
const tagsKV = TagUtils.proprtiesToKV(tags);
|
||||
|
@ -87,13 +93,20 @@ export class TagRenderingOptions {
|
|||
}
|
||||
|
||||
|
||||
construct(tags: UIEventSource<any>, changes: Changes): TagDependantUIElement {
|
||||
return new TagRendering(tags, changes, this.options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class TagRendering extends UIElement {
|
||||
class TagRendering extends UIElement implements TagDependantUIElement {
|
||||
|
||||
|
||||
public elementPriority: number;
|
||||
private _priority: number;
|
||||
|
||||
Priority(): number {
|
||||
return this._priority;
|
||||
}
|
||||
|
||||
private _question: string;
|
||||
private _primer: string;
|
||||
|
@ -142,12 +155,12 @@ export class TagRendering extends UIElement {
|
|||
this.ListenTo(this._editMode);
|
||||
|
||||
this._question = options.question;
|
||||
this._priority = options.priority ?? 0;
|
||||
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
|
||||
const choices: UIElement[] = [];
|
||||
|
|
20
Customizations/UIElementConstructor.ts
Normal file
20
Customizations/UIElementConstructor.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import {UIEventSource} from "../UI/UIEventSource";
|
||||
import {Changes} from "../Logic/Changes";
|
||||
import {UIElement} from "../UI/UIElement";
|
||||
|
||||
|
||||
export interface TagDependantUIElementConstructor {
|
||||
|
||||
construct(tags: UIEventSource<any>, changes: Changes): TagDependantUIElement;
|
||||
|
||||
}
|
||||
|
||||
export abstract class TagDependantUIElement extends UIElement {
|
||||
|
||||
abstract IsKnown(): boolean;
|
||||
|
||||
abstract IsQuestioning(): boolean;
|
||||
|
||||
abstract Priority() : number;
|
||||
|
||||
}
|
|
@ -23,7 +23,9 @@ export class Regex implements TagsFilter {
|
|||
return true;
|
||||
}
|
||||
|
||||
return tag.v.match(this._r).length > 0;
|
||||
|
||||
const matchCount =tag.v.match(this._r)?.length;
|
||||
return (matchCount ?? 0) > 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -6,10 +6,11 @@ import {ImageCarousel} from "./Image/ImageCarousel";
|
|||
import {Changes} from "../Logic/Changes";
|
||||
import {UserDetails} from "../Logic/OsmConnection";
|
||||
import {VerticalCombine} from "./Base/VerticalCombine";
|
||||
import {TagRendering, TagRenderingOptions} from "../Customizations/TagRendering";
|
||||
import {TagRenderingOptions} from "../Customizations/TagRendering";
|
||||
import {OsmLink} from "../Customizations/Questions/OsmLink";
|
||||
import {WikipediaLink} from "../Customizations/Questions/WikipediaLink";
|
||||
import {And} from "../Logic/TagsFilter";
|
||||
import {TagDependantUIElement} from "../Customizations/UIElementConstructor";
|
||||
|
||||
export class FeatureInfoBox extends UIElement {
|
||||
|
||||
|
@ -27,7 +28,7 @@ export class FeatureInfoBox extends UIElement {
|
|||
private _imageElement: ImageCarousel;
|
||||
private _pictureUploader: UIElement;
|
||||
private _wikipedialink: UIElement;
|
||||
private _infoboxes: TagRendering[];
|
||||
private _infoboxes: TagDependantUIElement[];
|
||||
|
||||
|
||||
constructor(
|
||||
|
@ -48,10 +49,8 @@ export class FeatureInfoBox extends UIElement {
|
|||
|
||||
this._infoboxes = [];
|
||||
for (const tagRenderingOption of elementsToShow) {
|
||||
if (tagRenderingOption.options === undefined) {
|
||||
throw "Tagrendering.options not defined"
|
||||
}
|
||||
this._infoboxes.push(new TagRendering(this._tagsES, this._changes, tagRenderingOption.options))
|
||||
this._infoboxes.push(
|
||||
tagRenderingOption.construct(this._tagsES, this._changes));
|
||||
}
|
||||
|
||||
title = title ?? new TagRenderingOptions(
|
||||
|
@ -60,10 +59,10 @@ export class FeatureInfoBox extends UIElement {
|
|||
}
|
||||
)
|
||||
|
||||
this._title = new TagRendering(this._tagsES, this._changes, title.options);
|
||||
this._title = new TagRenderingOptions(title.options).construct(this._tagsES, this._changes);
|
||||
|
||||
this._osmLink = new TagRendering(this._tagsES, this._changes, new OsmLink().options);
|
||||
this._wikipedialink = new TagRendering(this._tagsES, this._changes, new WikipediaLink().options);
|
||||
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();
|
||||
|
||||
|
@ -73,7 +72,7 @@ export class FeatureInfoBox extends UIElement {
|
|||
|
||||
|
||||
const info = [];
|
||||
const questions = [];
|
||||
const questions : TagDependantUIElement[] = [];
|
||||
|
||||
for (const infobox of this._infoboxes) {
|
||||
if (infobox.IsKnown()) {
|
||||
|
@ -92,9 +91,9 @@ export class FeatureInfoBox extends UIElement {
|
|||
let score = -1000;
|
||||
for (const question of questions) {
|
||||
|
||||
if (mostImportantQuestion === undefined || question.priority > score) {
|
||||
if (mostImportantQuestion === undefined || question.Priority() > score) {
|
||||
mostImportantQuestion = question;
|
||||
score = question.priority;
|
||||
score = question.Priority();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1
index.ts
1
index.ts
|
@ -27,6 +27,7 @@ import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
|||
|
||||
// --------------------- Read the URL parameters -----------------
|
||||
|
||||
// @ts-ignore
|
||||
if(location.href.startsWith("http://buurtnatuur.be")){
|
||||
// Reload the https version. This is important for the 'locate me' button
|
||||
window.location.replace("https://buurtnatuur.be");
|
||||
|
|
Loading…
Reference in a new issue