Merge branches
This commit is contained in:
commit
c1c11ed906
33 changed files with 568 additions and 130 deletions
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,8 +2,9 @@ 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";
|
||||
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
|
||||
|
||||
export class BikeParkings extends LayerDefinition {
|
||||
|
||||
|
@ -19,8 +20,9 @@ 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 ImageCarouselWithUploadConstructor(),
|
||||
new OperatorTag(),
|
||||
new BikeParkingType()
|
||||
];
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import {LayerDefinition} from "../LayerDefinition";
|
||||
import {And, Tag} from "../../Logic/TagsFilter";
|
||||
import * as L from "leaflet";
|
||||
import FixedName from "../Questions/FixedName";
|
||||
import BikeStationChain from "../Questions/BikeStationChain";
|
||||
import BikeStationPumpTools from "../Questions/BikeStationPumpTools";
|
||||
import BikeStationStand from "../Questions/BikeStationStand";
|
||||
import PumpManual from "../Questions/PumpManual";
|
||||
import BikeStationOperator from "../Questions/BikeStationOperator";
|
||||
import BikeStationBrand from "../Questions/BikeStationBrand";
|
||||
import FixedText from "../Questions/FixedText";
|
||||
import {BikePumpManometer} from "../Questions/BikePumpManometer";
|
||||
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
|
||||
|
||||
export default class BikeServices extends LayerDefinition {
|
||||
constructor() {
|
||||
|
@ -27,12 +29,22 @@ export default class BikeServices extends LayerDefinition {
|
|||
|
||||
this.minzoom = 13;
|
||||
this.style = this.generateStyleFunction();
|
||||
this.title = new FixedName("Bike station");
|
||||
this.title = new FixedText("Bike station");
|
||||
|
||||
const pump = new Tag("service:bicycle:pump", "yes");
|
||||
|
||||
this.elementsToShow = [
|
||||
|
||||
new ImageCarouselWithUploadConstructor(),
|
||||
|
||||
|
||||
new BikeStationPumpTools(),
|
||||
new BikeStationChain().OnlyShowIf(new Tag("service:bicycle:tools", "yes")),
|
||||
new BikeStationStand().OnlyShowIf(new Tag("service:bicycle:tools", "yes")),
|
||||
new PumpManual().OnlyShowIf(new Tag("service:bicycle:pump", "yes")),
|
||||
|
||||
new PumpManual().OnlyShowIf(pump),
|
||||
new BikePumpManometer().OnlyShowIf(pump),
|
||||
|
||||
new BikeStationOperator(),
|
||||
new BikeStationBrand()
|
||||
];
|
||||
|
|
|
@ -145,7 +145,7 @@ export class Bookcases extends LayerDefinition {
|
|||
new TagRenderingOptions({
|
||||
freeform: {
|
||||
key: "description",
|
||||
renderTemplate: "<b>Beschrijving door de uitbater</b><br>{description}",
|
||||
renderTemplate: "<b>Beschrijving door de uitbater:</b><br>{description}",
|
||||
template: "$$$",
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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(),
|
||||
|
|
69
Customizations/Layers/GhostBike.ts
Normal file
69
Customizations/Layers/GhostBike.ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
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 <b>ghost bike</b> 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(),
|
||||
|
||||
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>",
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
|
||||
];
|
||||
|
||||
this.style = (tags: any) => {
|
||||
return {
|
||||
color: "#000000",
|
||||
icon: L.icon({
|
||||
iconUrl: 'assets/ghost_bike.svg',
|
||||
iconSize: [40, 40],
|
||||
iconAnchor: [20, 20],
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -16,7 +16,21 @@ export class Layout {
|
|||
public startLat: number;
|
||||
public welcomeTail: string;
|
||||
|
||||
public locationContains: string[];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name: The name used in the query string. If in the query "quests=<name>" is defined, it will select this layout
|
||||
* @param title: Will be used in the <title> 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,
|
||||
|
@ -25,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;
|
||||
|
@ -41,13 +55,5 @@ export class Layout {
|
|||
this.welcomeTail = welcomeTail;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
static statues = new Layout(
|
||||
|
||||
);
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
|
@ -23,5 +23,6 @@ export class Bookcases extends Layout{
|
|||
" </a> of door je " +
|
||||
" <span onclick=\"authOsm()\" class=\"activate-osm-authentication\">aan te melden</span>.</p>",
|
||||
"Klik op een boekenruilkastje om vragen te beantwoorden");
|
||||
this.locationContains= ["Bookcases.html", "Bookcase.html","bookcase"]
|
||||
}
|
||||
}
|
|
@ -2,13 +2,15 @@ import {Layout} from "../Layout";
|
|||
import {GrbToFix} from "../Layers/GrbToFix";
|
||||
import { BikeParkings } from "../Layers/BikeParkings";
|
||||
import BikeServices from "../Layers/BikeServices";
|
||||
import {GhostBike} from "../Layers/GhostBike";
|
||||
|
||||
export default class Cyclofix extends Layout {
|
||||
constructor() {
|
||||
super(
|
||||
"pomp",
|
||||
"Cyclofix bicycle infrastructure",
|
||||
[new BikeParkings(), new BikeServices()],
|
||||
// [new BikePumps()],
|
||||
[new GhostBike(), new BikeParkings(), new BikeServices()],
|
||||
16,
|
||||
50.8465573,
|
||||
4.3516970,
|
||||
|
|
|
@ -47,5 +47,7 @@ export class Groen extends Layout {
|
|||
"Als je inlogt, komt er een tweede cookie bij met je inloggegevens." +
|
||||
"</small>"
|
||||
);
|
||||
|
||||
this.locationContains = ["buurtnatuur.be"]
|
||||
}
|
||||
}
|
20
Customizations/Questions/BikePumpManometer.ts
Normal file
20
Customizations/Questions/BikePumpManometer.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import {TagRenderingOptions} from "../TagRendering";
|
||||
import {Tag} from "../../Logic/TagsFilter";
|
||||
|
||||
export class BikePumpManometer extends TagRenderingOptions{
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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","broken"), txt: "Yes, but it is broken"},
|
||||
{k: new Tag("manometer", "yes"), txt: "No"}
|
||||
]
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
24
Customizations/Questions/BikePumpValves.ts
Normal file
24
Customizations/Questions/BikePumpValves.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import {TagRenderingOptions} from "../TagRendering";
|
||||
import {Tag} from "../../Logic/TagsFilter";
|
||||
|
||||
export class BikePumpValves extends TagRenderingOptions{
|
||||
constructor() {
|
||||
super({
|
||||
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}"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ export default class BikeStationOperator extends TagRenderingOptions {
|
|||
{k: new Tag("operator", "KU Leuven"), txt: "KU Leuven"},
|
||||
{k: new Tag("operator", "Stad Halle"), txt: "Stad Halle"},
|
||||
{k: new Tag("operator", "Saint Gilles - Sint Gillis"), txt: "Saint Gilles - Sint Gillis"},
|
||||
{k: new Tag("operator", "Jette"), txt: "Jette"},
|
||||
{k: new Tag("operator", "private"), txt: "Beheer door een privépersoon"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ export class DescriptionQuestion extends TagRenderingOptions{
|
|||
super({
|
||||
question: "Zijn er bijzonderheden die we moeten weten over dit "+category+"?<br>" +
|
||||
"<span class='question-subtext'>Je hoeft niet te herhalen wat je net hebt aangeduid.<br/>" +
|
||||
"Een <i>naam</i> wordt in de volgende stap gevraagd.<br/>" +
|
||||
"Voel je vrij om dit veld over te slaan.</span>",
|
||||
freeform:{
|
||||
key:"description:0",
|
||||
|
|
|
@ -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: [
|
|
@ -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 {
|
||||
|
||||
|
@ -26,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.
|
||||
|
@ -41,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'
|
||||
|
@ -64,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;
|
||||
}
|
||||
|
@ -111,6 +129,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
|||
|
||||
|
||||
private _priority: number;
|
||||
private _userDetails: UIEventSource<UserDetails>;
|
||||
|
||||
Priority(): number {
|
||||
return this._priority;
|
||||
|
@ -162,6 +181,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 +419,14 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
|||
if (html == "") {
|
||||
return "";
|
||||
}
|
||||
let editButton = "";
|
||||
if(this._userDetails.data.loggedIn){
|
||||
editButton = this._editButton.Render();
|
||||
}
|
||||
|
||||
return "<span class='answer'>" +
|
||||
"<span class='answer-text'>" + html + "</span>" + this._editButton.Render() +
|
||||
"<span class='answer-text'>" + html + "</span>" +
|
||||
editButton +
|
||||
"</span>";
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,7 +13,6 @@ export class UserDetails {
|
|||
public osmConnection: OsmConnection;
|
||||
public dryRun: boolean;
|
||||
home: { lon: number; lat: number };
|
||||
|
||||
}
|
||||
|
||||
export class OsmConnection {
|
||||
|
@ -121,6 +120,29 @@ export class OsmConnection {
|
|||
}
|
||||
|
||||
public preferences = new UIEventSource<any>({});
|
||||
public preferenceSources : any = {}
|
||||
|
||||
public GetPreference(key: string) : UIEventSource<string>{
|
||||
if(this.preferenceSources[key] !== undefined){
|
||||
return this.preferenceSources[key];
|
||||
}
|
||||
this.UpdatePreferences();
|
||||
console.log("Getting preference object", key, "currently upstreamed as ",this.preferences.data[key] );
|
||||
const pref = new UIEventSource<string>(this.preferences.data[key]);
|
||||
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,13 +164,14 @@ 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;
|
||||
}
|
||||
|
||||
if (this.preferences.data[k] === v) {
|
||||
console.log("Not updating preference", k, " to ", v, "not changed");
|
||||
return;
|
||||
}
|
||||
console.log("Updating preference", k, " to ", v);
|
||||
|
@ -166,7 +189,7 @@ export class OsmConnection {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log("Preference written!", result);
|
||||
console.log("Preference written!", result == "" ? "OK" : result);
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -15,29 +15,25 @@ import {TagDependantUIElement} from "../Customizations/UIElementConstructor";
|
|||
export class FeatureInfoBox extends UIElement {
|
||||
|
||||
private _tagsES: UIEventSource<any>;
|
||||
private _changes: Changes;
|
||||
private _userDetails: UIEventSource<UserDetails>;
|
||||
|
||||
|
||||
private _title: UIElement;
|
||||
private _osmLink: UIElement;
|
||||
|
||||
|
||||
private _questions: QuestionPicker;
|
||||
|
||||
private _changes: Changes;
|
||||
private _userDetails: UIEventSource<UserDetails>;
|
||||
private _imageElement: ImageCarousel;
|
||||
private _pictureUploader: UIElement;
|
||||
private _wikipedialink: UIElement;
|
||||
private _infoboxes: TagDependantUIElement[];
|
||||
|
||||
|
||||
|
||||
private _infoboxes: TagDependantUIElement[];
|
||||
private _questions: QuestionPicker;
|
||||
|
||||
constructor(
|
||||
tagsES: UIEventSource<any>,
|
||||
title: TagRenderingOptions,
|
||||
elementsToShow: TagRenderingOptions[],
|
||||
changes: Changes,
|
||||
userDetails: UIEventSource<UserDetails>,
|
||||
preferedPictureLicense: UIEventSource<string>
|
||||
userDetails: UIEventSource<UserDetails>
|
||||
) {
|
||||
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 {
|
|||
"</div>" +
|
||||
|
||||
"<div class='infoboxcontents'>" +
|
||||
|
||||
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();
|
||||
|
|
|
@ -7,8 +7,30 @@ import {VerticalCombine} from "../Base/VerticalCombine";
|
|||
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<any>, changes: Changes): TagDependantUIElement {
|
||||
return new ImageCarousel(tags, changes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ImageCarousel extends TagDependantUIElement {
|
||||
|
||||
export class ImageCarousel extends UIElement {
|
||||
|
||||
private readonly searcher: ImageSearcher;
|
||||
|
||||
|
@ -19,8 +41,11 @@ export class ImageCarousel extends UIElement {
|
|||
private readonly _deleteButton: UIElement;
|
||||
private readonly _isDeleted: UIElement;
|
||||
|
||||
private readonly _userDetails : UIEventSource<UserDetails>;
|
||||
|
||||
constructor(tags: UIEventSource<any>, changes: Changes) {
|
||||
super(tags);
|
||||
this._userDetails = changes.login.userDetails;
|
||||
|
||||
const self = this;
|
||||
this.searcher = new ImageSearcher(tags, changes);
|
||||
|
@ -40,8 +65,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 +85,7 @@ export class ImageCarousel extends UIElement {
|
|||
"<span>Afbeelding verwijderen</span>",
|
||||
"<span>Terug</span>",
|
||||
deleteCurrent,
|
||||
() => {
|
||||
},
|
||||
() => { },
|
||||
'delete-image-confirm',
|
||||
'delete-image-cancel');
|
||||
|
||||
|
@ -75,7 +102,6 @@ export class ImageCarousel extends UIElement {
|
|||
this._isDeleted = new VariableUiElement(
|
||||
mapping
|
||||
)
|
||||
// .HideOnEmpty(true);
|
||||
|
||||
this.searcher._deletedImages.addCallback(() => {
|
||||
this.slideshow._currentSlide.ping();
|
||||
|
@ -93,6 +119,18 @@ export class ImageCarousel extends UIElement {
|
|||
"</span>";
|
||||
}
|
||||
|
||||
IsKnown(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
IsQuestioning(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
Priority(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
InnerUpdate(htmlElement: HTMLElement) {
|
||||
super.InnerUpdate(htmlElement);
|
||||
this._deleteButton.Update();
|
||||
|
|
71
UI/Image/ImageCarouselWithUpload.ts
Normal file
71
UI/Image/ImageCarouselWithUpload.ts
Normal file
|
@ -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<any>, changes: Changes): TagDependantUIElement {
|
||||
return new ImageCarouselWithUpload(tags, changes);
|
||||
}
|
||||
}
|
||||
|
||||
class ImageCarouselWithUpload extends TagDependantUIElement {
|
||||
private _imageElement: ImageCarousel;
|
||||
private _pictureUploader: ImageUploadFlow;
|
||||
|
||||
constructor(tags: UIEventSource<any>, 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
20
assets/Buurtnatuur-Welkom.txt
Normal file
20
assets/Buurtnatuur-Welkom.txt
Normal file
|
@ -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ë
|
92
assets/ghost_bike.svg
Normal file
92
assets/ghost_bike.svg
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="2"
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 50 50"
|
||||
id="svg4"
|
||||
sodipodi:docname="ghost_bike.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1001"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4.72"
|
||||
inkscape:cx="-40.53625"
|
||||
inkscape:cy="33.532739"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="background"
|
||||
sodipodi:insensitive="true">
|
||||
<ellipse
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:50;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path839"
|
||||
cx="25"
|
||||
cy="24.894068"
|
||||
rx="25"
|
||||
ry="25.105932" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="bicycle">
|
||||
<path
|
||||
d="m 37.198846,28.51624 c -0.865699,0 -1.688316,0.177789 -2.435717,0.497127 l -2.103385,-3.60434 1.58506,-2.71676 c 0.215399,-0.370622 0.09027,-0.846552 -0.279675,-1.063319 -0.162747,-0.09437 -0.343955,-0.265316 -0.515591,-0.237279 l -0.134709,-0.158644 h -3.109265 c -0.428746,0 -0.776803,0.596963 -0.776803,1.02571 0,0.429429 0.348057,1.025708 0.776803,1.025708 h 2.015176 l -0.90741,1.367611 h -9.079572 l 1.813452,-3.419029 h 0.718681 c 0.428746,0 0.776802,-0.254375 0.776802,-0.683806 0,-0.42943 -0.348056,-0.683806 -0.776802,-0.683806 h -3.886069 c -0.428061,0 -0.776803,0.254376 -0.776803,0.683806 0,0.429431 0.348057,0.683806 0.776803,0.683806 h 1.366929 l -4.368835,7.634691 c -0.748084,-0.319337 -1.572071,-0.423959 -2.437085,-0.423959 -3.432704,0 -6.2157926,2.820014 -6.2157926,6.252718 0,3.433389 2.7830886,6.234257 6.2164776,6.234257 3.433388,0 6.216478,-2.774199 6.216478,-6.207588 0,-2.010389 -0.958697,-3.788967 -2.441187,-4.926136 l 1.663699,-2.848735 4.768861,8.17558 0.01847,0.02598 0.02051,0.03077 0.01572,0.02325 0.06154,0.07111 0.0076,0.0089 0.0212,0.01915 0.02188,0.01777 0.06017,0.04787 0.0253,0.01641 0.01983,0.01298 0.0082,0.0048 0.0027,0.0027 0.06564,0.03214 0.0076,0.0033 0.01573,0.0082 0.0054,0.0014 0.04992,0.01778 0.0465,0.01505 0.0095,0.0027 0.01709,0.0027 0.03008,0.0062 0.139496,0.01436 6.84e-4,0.04239 0.0027,0.04034 h 4.712106 c 0.384299,2.735223 2.9937,5.398646 6.16314,5.398646 3.433388,0 6.216478,-2.804288 6.216478,-6.237676 6.83e-4,-3.432704 -2.782407,-6.236991 -6.215794,-6.236991 z m -17.095143,6.216477 c 0,2.575896 -2.086974,4.662872 -4.662187,4.662872 -2.575213,0 -4.662188,-2.087659 -4.662188,-4.662872 0,-2.574528 2.086975,-4.661503 4.662188,-4.661503 0.579183,0 1.131698,0.110088 1.643185,0.30361 l -2.314683,3.96744 c -0.216082,0.369938 -0.09027,0.845868 0.280362,1.063319 0.123084,0.07111 0.257794,0.10531 0.390451,0.10531 0.267369,0 0.527215,-0.13813 0.672182,-0.384984 l 2.315367,-3.970175 c 1.022972,0.855441 1.675323,2.140312 1.675323,3.576987 z m 6.216477,-1.708146 -4.086422,-7.004905 h 8.173529 z m 5.438991,-5.938853 1.664383,2.918483 c -1.286923,0.987416 -2.17587,2.169715 -2.38785,4.221133 h -3.362956 z m 2.452811,4.338747 1.634979,2.800869 H 32.60709 c 0.187363,-1.367612 0.769965,-2.102702 1.604892,-2.800869 z m 2.986864,8.01352 c -2.309212,0 -4.222501,-1.793624 -4.592439,-3.84504 h 4.590387 l 0.0033,-0.04035 0.138811,-0.03624 0.03145,-0.01572 0.129239,-0.04513 0.01436,-0.01089 0.07727,-0.03966 0.01847,-0.01436 0.06907,-0.04992 0.05334,-0.04513 0.05197,-0.05675 0.0465,-0.05813 0.03898,-0.06292 0.03556,-0.06496 0.02667,-0.07111 0.0212,-0.07111 0.01164,-0.07111 0.0089,-0.08411 0.002,-0.02394 -0.0033,-0.04377 -0.0095,-0.0848 -0.01573,-0.07248 -0.02257,-0.07111 -0.03556,-0.07726 -0.01847,-0.04035 -2.314683,-3.96744 c 0.512856,-0.193517 1.064686,-0.30361 1.643186,-0.30361 2.575896,0 4.662871,2.108172 4.662871,4.682701 6.83e-4,2.575896 -2.086975,4.684753 -4.662871,4.684753 z"
|
||||
id="path2"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.6838057"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
id="g861"
|
||||
transform="translate(-10.037321,-26.552854)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path842"
|
||||
d="M 25.018397,35.018924 V 47.003785"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path842-3"
|
||||
d="M 28.86857,39.213625 H 20.748791"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1.64621139;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="cross" />
|
||||
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -48,15 +48,6 @@
|
|||
<script src="./index.ts"></script>
|
||||
<script src="vendor/Leaflet.AccuratePosition.js"></script>
|
||||
|
||||
<!-- 3 dagen eerste protoype -->
|
||||
<!-- 19 juni: eerste feedbackronde, foto's -->
|
||||
<!-- 23 juni: wikimedia foto's laden -->
|
||||
<!-- 24 juni: foto's via imgur -->
|
||||
|
||||
<!-- 26 restylen infobox -->
|
||||
<!-- 27 restylen infobox, flow UI verbeteren, mobile, locate-me -->
|
||||
|
||||
<!-- 28: user testing, fixing issues and faults, lots of small useless features, add button vs 2.0 -->
|
||||
<script data-goatcounter="https://pietervdvn.goatcounter.com/count"
|
||||
async src="//gc.zgo.at/count.js"></script>
|
||||
|
||||
|
|
81
index.ts
81
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";
|
||||
|
||||
|
||||
|
||||
|
@ -49,26 +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 ?? [];
|
||||
for (const locationMatch of possibleParts) {
|
||||
if (locationMatch === "") {
|
||||
continue
|
||||
}
|
||||
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.layout) {
|
||||
defaultLayout = paramDict.layout
|
||||
}
|
||||
|
||||
if (paramDict.test) {
|
||||
dryRun = true;
|
||||
}
|
||||
}
|
||||
|
||||
const questSetToRender = AllKnownLayouts.allSets[defaultQuest];
|
||||
console.log("Using quests: ", questSetToRender.name);
|
||||
const layoutToUse = AllKnownLayouts.allSets[defaultLayout];
|
||||
console.log("Using layout: ", layoutToUse.name);
|
||||
|
||||
document.title = questSetToRender.title;
|
||||
document.title = layoutToUse.title;
|
||||
|
||||
|
||||
// ----------------- Setup a few event sources -------------
|
||||
|
@ -84,12 +106,11 @@ const leftMessage = new UIEventSource<() => UIElement>(undefined);
|
|||
|
||||
const selectedElement = new UIEventSource<any>(undefined);
|
||||
|
||||
const preferedPictureLicense = new UIEventSource<string>(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
|
||||
});
|
||||
|
||||
|
||||
|
@ -99,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) => {
|
||||
|
@ -119,21 +140,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: {
|
||||
|
@ -148,7 +154,7 @@ const flayers: FilteredLayer[] = []
|
|||
|
||||
let minZoom = 0;
|
||||
|
||||
for (const layer of questSetToRender.layers) {
|
||||
for (const layer of layoutToUse.layers) {
|
||||
|
||||
const generateInfo = (tagsES) => {
|
||||
|
||||
|
@ -157,15 +163,13 @@ for (const layer of questSetToRender.layers) {
|
|||
layer.title,
|
||||
layer.elementsToShow,
|
||||
changes,
|
||||
osmConnection.userDetails,
|
||||
preferedPictureLicense
|
||||
osmConnection.userDetails
|
||||
)
|
||||
};
|
||||
|
||||
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,
|
||||
|
@ -199,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) {
|
||||
|
@ -210,8 +214,7 @@ selectedElement.addCallback((data) => {
|
|||
layer.title,
|
||||
layer.elementsToShow,
|
||||
changes,
|
||||
osmConnection.userDetails,
|
||||
preferedPictureLicense
|
||||
osmConnection.userDetails
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
@ -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 () {
|
||||
|
|
8
test.ts
8
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)
|
Loading…
Reference in a new issue