forked from MapComplete/MapComplete
		
	Merge branch 'master' of github.com:pietervdvn/MapComplete
This commit is contained in:
		
						commit
						1f98cd568f
					
				
					 37 changed files with 316 additions and 279 deletions
				
			
		| 
						 | 
					@ -15,7 +15,7 @@ export class LayerDefinition {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * This name is shown in the 'add XXX button'
 | 
					     * This name is shown in the 'add XXX button'
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    name: string;
 | 
					    name: string | UIElement;
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * These tags are added whenever a new point is added by the user on the map.
 | 
					     * 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"
 | 
					     * This is the ideal place to add extra info, such as "fixme=added by MapComplete, geometry should be checked"
 | 
				
			||||||
| 
						 | 
					@ -72,6 +72,14 @@ export class LayerDefinition {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    maxAllowedOverlapPercentage: number = undefined;
 | 
					    maxAllowedOverlapPercentage: number = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * If true, then ways (and polygons) will be converted to a 'point' at the center instead before further processing
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    wayHandling: number = 0;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    static WAYHANDLING_DEFAULT = 0;
 | 
				
			||||||
 | 
					    static WAYHANDLING_CENTER_ONLY = 1;
 | 
				
			||||||
 | 
					    static WAYHANDLING_CENTER_AND_WAY = 2;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    constructor(options: {
 | 
					    constructor(options: {
 | 
				
			||||||
        name: string,
 | 
					        name: string,
 | 
				
			||||||
| 
						 | 
					@ -82,6 +90,7 @@ export class LayerDefinition {
 | 
				
			||||||
        title?: TagRenderingOptions,
 | 
					        title?: TagRenderingOptions,
 | 
				
			||||||
        elementsToShow?: TagDependantUIElementConstructor[],
 | 
					        elementsToShow?: TagDependantUIElementConstructor[],
 | 
				
			||||||
        maxAllowedOverlapPercentage?: number,
 | 
					        maxAllowedOverlapPercentage?: number,
 | 
				
			||||||
 | 
					        wayHandling?: number,
 | 
				
			||||||
        style?: (tags: any) => {
 | 
					        style?: (tags: any) => {
 | 
				
			||||||
            color: string,
 | 
					            color: string,
 | 
				
			||||||
            icon: any
 | 
					            icon: any
 | 
				
			||||||
| 
						 | 
					@ -99,16 +108,19 @@ export class LayerDefinition {
 | 
				
			||||||
        this.title = options.title;
 | 
					        this.title = options.title;
 | 
				
			||||||
        this.elementsToShow = options.elementsToShow;
 | 
					        this.elementsToShow = options.elementsToShow;
 | 
				
			||||||
        this.style = options.style;
 | 
					        this.style = options.style;
 | 
				
			||||||
 | 
					        this.wayHandling = options.wayHandling ?? LayerDefinition.WAYHANDLING_DEFAULT;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    asLayer(basemap: Basemap, allElements: ElementStorage, changes: Changes, userDetails: UIEventSource<UserDetails>, selectedElement: UIEventSource<any>,
 | 
					    asLayer(basemap: Basemap, allElements: ElementStorage, changes: Changes, userDetails: UIEventSource<UserDetails>,
 | 
				
			||||||
            showOnPopup: (tags: UIEventSource<(any)>) => UIElement):
 | 
					            selectedElement: UIEventSource<{feature: any}>,
 | 
				
			||||||
 | 
					            showOnPopup: (tags: UIEventSource<(any)>, feature: any) => UIElement):
 | 
				
			||||||
        FilteredLayer {
 | 
					        FilteredLayer {
 | 
				
			||||||
        return new FilteredLayer(
 | 
					        return new FilteredLayer(
 | 
				
			||||||
            this.name,
 | 
					            this.name,
 | 
				
			||||||
            basemap, allElements, changes,
 | 
					            basemap, allElements, changes,
 | 
				
			||||||
            this.overpassFilter,
 | 
					            this.overpassFilter,
 | 
				
			||||||
            this.maxAllowedOverlapPercentage,
 | 
					            this.maxAllowedOverlapPercentage,
 | 
				
			||||||
 | 
					            this.wayHandling,
 | 
				
			||||||
            this.style,
 | 
					            this.style,
 | 
				
			||||||
            selectedElement,
 | 
					            selectedElement,
 | 
				
			||||||
            showOnPopup);
 | 
					            showOnPopup);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ import ParkingOperator from "../Questions/bike/ParkingOperator";
 | 
				
			||||||
export default class BikeParkings extends LayerDefinition {
 | 
					export default class BikeParkings extends LayerDefinition {
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        super();
 | 
					        super();
 | 
				
			||||||
        this.name = Translations.t.cyclofix.parking.name.txt;
 | 
					        this.name = Translations.t.cyclofix.parking.name;
 | 
				
			||||||
        this.icon = "./assets/bike/parking.svg";
 | 
					        this.icon = "./assets/bike/parking.svg";
 | 
				
			||||||
        this.overpassFilter = new Tag("amenity", "bicycle_parking");
 | 
					        this.overpassFilter = new Tag("amenity", "bicycle_parking");
 | 
				
			||||||
        this.newElementTags = [
 | 
					        this.newElementTags = [
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@ export default class BikeParkings extends LayerDefinition {
 | 
				
			||||||
            //new ParkingOperator(),
 | 
					            //new ParkingOperator(),
 | 
				
			||||||
            new ParkingType()
 | 
					            new ParkingType()
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					        this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,122 +0,0 @@
 | 
				
			||||||
import {TagRenderingOptions} from "../TagRendering";
 | 
					 | 
				
			||||||
import {LayerDefinition} from "../LayerDefinition";
 | 
					 | 
				
			||||||
import {And, Tag} from "../../Logic/TagsFilter";
 | 
					 | 
				
			||||||
import L from "leaflet";
 | 
					 | 
				
			||||||
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
 | 
					 | 
				
			||||||
import {NameQuestion} from "../Questions/NameQuestion";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export class BikeShop extends LayerDefinition {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private readonly sellsBikes = new Tag("service:bicycle:retail", "yes");
 | 
					 | 
				
			||||||
    private readonly repairsBikes = new Tag("service:bicycle:repair", "yes");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    constructor() {
 | 
					 | 
				
			||||||
        super(
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                name: "bike shop or repair",
 | 
					 | 
				
			||||||
                icon: "assets/bike/repair_shop.svg",
 | 
					 | 
				
			||||||
                minzoom: 14,
 | 
					 | 
				
			||||||
                overpassFilter: new Tag("shop", "bicycle"),
 | 
					 | 
				
			||||||
                newElementTags: [new Tag("shop", "bicycle")]
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.title = new TagRenderingOptions({
 | 
					 | 
				
			||||||
            mappings: [
 | 
					 | 
				
			||||||
                {k: new And([new Tag("name", "*"), this.sellsBikes]), txt: "Bicycle shop {name}"},
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "no")]),
 | 
					 | 
				
			||||||
                    txt: "Bicycle repair {name}",
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "")]),
 | 
					 | 
				
			||||||
                    txt: "Bicycle repair {name}"
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                {k: this.sellsBikes, txt: "Bicycle shop"},
 | 
					 | 
				
			||||||
                {k: new Tag("service:bicycle:retail", "no"), txt: "Bicycle repair"},
 | 
					 | 
				
			||||||
                {k: new Tag("service:bicycle:retail", ""), txt: "Bicycle repair/shop"},
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        this.elementsToShow = [
 | 
					 | 
				
			||||||
            new ImageCarouselWithUploadConstructor(),
 | 
					 | 
				
			||||||
            new TagRenderingOptions({
 | 
					 | 
				
			||||||
                question: "What is the name of this bicycle shop?",
 | 
					 | 
				
			||||||
                freeform: {
 | 
					 | 
				
			||||||
                    key: "name",
 | 
					 | 
				
			||||||
                    renderTemplate: "The name of this bicycle shop is {name}",
 | 
					 | 
				
			||||||
                    template: "The name of this bicycle shop is $$$"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new TagRenderingOptions({
 | 
					 | 
				
			||||||
                question: "Can one buy a bike here?",
 | 
					 | 
				
			||||||
                mappings: [
 | 
					 | 
				
			||||||
                    {k: this.sellsBikes, txt: "Bikes are sold here"},
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:retail", "no"), txt: "No bikes are sold here"},
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new TagRenderingOptions({
 | 
					 | 
				
			||||||
                question: "Can one buy a new bike here?",
 | 
					 | 
				
			||||||
                mappings: [
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:second_hand", "yes"), txt: "Second-hand bikes are sold here"},
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:second_hand", "only"), txt: "All bicycles sold here are second-hand"},
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:second_hand", "no"), txt: "Only brand new bikes are sold here"},
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
            }).OnlyShowIf(this.sellsBikes),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new TagRenderingOptions({
 | 
					 | 
				
			||||||
                question: "Does this shop repair bicycles?",
 | 
					 | 
				
			||||||
                mappings: [
 | 
					 | 
				
			||||||
                    {k: this.repairsBikes, txt: "Bikes are repaired here, by the shop owner (for a fee)"},
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:repair", "only_sold"), txt: "Only bikes that were bought here, are repaired"},
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:repair", "brand"), txt: "Only bikes of a fixed brand are repaired here"},
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:repair", "no"), txt: "Bikes are not repaired here"},
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new TagRenderingOptions({
 | 
					 | 
				
			||||||
                question: "Can one hire a new bike here?",
 | 
					 | 
				
			||||||
                mappings: [
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:rental", "yes"), txt: "Bikes can be rented here"},
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:rental", "no"), txt:  "Bikes cannot be rented here"},
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
            }).OnlyShowIf(this.sellsBikes),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new TagRenderingOptions({
 | 
					 | 
				
			||||||
                question: "Are there tools here so that one can repair their own bike?",
 | 
					 | 
				
			||||||
                mappings: [
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:diy", "yes"), txt: "Tools for DIY are available here"},
 | 
					 | 
				
			||||||
                    {k: new Tag("service:bicycle:diy", "no"), txt: "No tools for DIY are available here"},
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.style = (tags) => {
 | 
					 | 
				
			||||||
            let icon = "assets/bike/repair_shop.svg";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (this.sellsBikes.matchesProperties(tags)) {
 | 
					 | 
				
			||||||
                icon = "assets/bike/shop.svg";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return {
 | 
					 | 
				
			||||||
                color: "#ff0000",
 | 
					 | 
				
			||||||
                icon: L.icon({
 | 
					 | 
				
			||||||
                    iconUrl: icon,
 | 
					 | 
				
			||||||
                    iconSize: [50, 50],
 | 
					 | 
				
			||||||
                    iconAnchor: [25, 50]
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
import { LayerDefinition } from "../LayerDefinition";
 | 
					import { LayerDefinition } from "../LayerDefinition";
 | 
				
			||||||
import Translations from "../../UI/i18n/Translations";
 | 
					import Translations from "../../UI/i18n/Translations";
 | 
				
			||||||
import { Tag } from "../../Logic/TagsFilter";
 | 
					import {And, Tag} from "../../Logic/TagsFilter";
 | 
				
			||||||
import FixedText from "../Questions/FixedText";
 | 
					import FixedText from "../Questions/FixedText";
 | 
				
			||||||
import { ImageCarouselWithUploadConstructor } from "../../UI/Image/ImageCarouselWithUpload";
 | 
					import { ImageCarouselWithUploadConstructor } from "../../UI/Image/ImageCarouselWithUpload";
 | 
				
			||||||
import * as L from "leaflet";
 | 
					import * as L from "leaflet";
 | 
				
			||||||
| 
						 | 
					@ -20,33 +20,42 @@ export default class BikeShops extends LayerDefinition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        super();
 | 
					        super();
 | 
				
			||||||
        this.name = Translations.t.cyclofix.shop.name.txt
 | 
					        this.name = Translations.t.cyclofix.shop.name
 | 
				
			||||||
        this.icon = "./assets/bike/repair_shop.svg"
 | 
					        this.icon = "./assets/bike/repair_shop.svg"
 | 
				
			||||||
        this.overpassFilter = new Tag("shop", "bicycle");
 | 
					        this.overpassFilter = new Tag("shop", "bicycle");
 | 
				
			||||||
        this.newElementTags = [
 | 
					        this.newElementTags = [
 | 
				
			||||||
            new Tag("shop", "bicycle"),
 | 
					            new Tag("shop", "bicycle"),
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        this.maxAllowedOverlapPercentage = 10
 | 
					        this.maxAllowedOverlapPercentage = 10
 | 
				
			||||||
 | 
					        this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.minzoom = 13;
 | 
					        this.minzoom = 13;
 | 
				
			||||||
        this.style = this.generateStyleFunction();
 | 
					        this.style = this.generateStyleFunction();
 | 
				
			||||||
        this.title = new TagRenderingOptions({
 | 
					        this.title = new TagRenderingOptions({
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: this.sellsBikes, txt: "Bicycle shop"},
 | 
					                {k: new And([new Tag("name", "*"), this.sellsBikes]), txt: Translations.t.cyclofix.shop.titleShopNamed},
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "")]),
 | 
				
			||||||
 | 
					                    txt: Translations.t.cyclofix.shop.titleShop
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "no")]),
 | 
				
			||||||
 | 
					                    txt: Translations.t.cyclofix.shop.titleRepairNamed
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {k: this.sellsBikes, txt: Translations.t.cyclofix.shop.titleShop},
 | 
				
			||||||
 | 
					                {k: new Tag("service:bicycle:retail", " "), txt: Translations.t.cyclofix.shop.title},
 | 
				
			||||||
                {k: new Tag("service:bicycle:retail", "no"), txt: Translations.t.cyclofix.shop.titleRepair},
 | 
					                {k: new Tag("service:bicycle:retail", "no"), txt: Translations.t.cyclofix.shop.titleRepair},
 | 
				
			||||||
                {k: new Tag("service:bicycle:retail", ""), txt: Translations.t.cyclofix.shop.title},
 | 
					 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        this.elementsToShow = [
 | 
					        this.elementsToShow = [
 | 
				
			||||||
            new ImageCarouselWithUploadConstructor(),
 | 
					            new ImageCarouselWithUploadConstructor(),
 | 
				
			||||||
            //new ParkingOperator(),
 | 
					            new ShopName(),
 | 
				
			||||||
            new ShopRetail(),
 | 
					            new ShopRetail(),
 | 
				
			||||||
            new ShopRental(),
 | 
					            new ShopRental(),
 | 
				
			||||||
            new ShopRepair(),
 | 
					            new ShopRepair(),
 | 
				
			||||||
            new ShopPump(),
 | 
					            new ShopPump(),
 | 
				
			||||||
            new ShopDiy(),
 | 
					            new ShopDiy(),
 | 
				
			||||||
            new ShopName(),
 | 
					 | 
				
			||||||
            new ShopSecondHand()
 | 
					            new ShopSecondHand()
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ export default class BikeStations extends LayerDefinition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        super();
 | 
					        super();
 | 
				
			||||||
        this.name = Translations.t.cyclofix.station.name.txt;
 | 
					        this.name = Translations.t.cyclofix.station.name;
 | 
				
			||||||
        this.icon = "./assets/wrench.svg";
 | 
					        this.icon = "./assets/wrench.svg";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.overpassFilter = new And([
 | 
					        this.overpassFilter = new And([
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,8 @@ export default class BikeStations extends LayerDefinition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.minzoom = 13;
 | 
					        this.minzoom = 13;
 | 
				
			||||||
        this.style = this.generateStyleFunction();
 | 
					        this.style = this.generateStyleFunction();
 | 
				
			||||||
        this.title = new FixedText(Translations.t.cyclofix.station.title.txt)
 | 
					        this.title = new FixedText(Translations.t.cyclofix.station.title)
 | 
				
			||||||
 | 
					        this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.elementsToShow = [
 | 
					        this.elementsToShow = [
 | 
				
			||||||
            new ImageCarouselWithUploadConstructor(),
 | 
					            new ImageCarouselWithUploadConstructor(),
 | 
				
			||||||
| 
						 | 
					@ -62,24 +63,19 @@ export default class BikeStations extends LayerDefinition {
 | 
				
			||||||
            const hasPump = self.pump.matchesProperties(properties)
 | 
					            const hasPump = self.pump.matchesProperties(properties)
 | 
				
			||||||
            const isOperational = self.pumpOperationalOk.matchesProperties(properties)
 | 
					            const isOperational = self.pumpOperationalOk.matchesProperties(properties)
 | 
				
			||||||
            const hasTools = self.tools.matchesProperties(properties)
 | 
					            const hasTools = self.tools.matchesProperties(properties)
 | 
				
			||||||
            let iconName = ""
 | 
					            let iconName = "repair_station.svg";
 | 
				
			||||||
            if (hasPump) {
 | 
					            if (hasTools && hasPump && isOperational) {
 | 
				
			||||||
                if (hasTools) {
 | 
					 | 
				
			||||||
                iconName = "repair_station_pump.svg"
 | 
					                iconName = "repair_station_pump.svg"
 | 
				
			||||||
                } else {
 | 
					            }else if(hasTools){
 | 
				
			||||||
 | 
					                    iconName = "repair_station.svg"
 | 
				
			||||||
 | 
					            }else if(hasPump){
 | 
				
			||||||
                if (isOperational) {
 | 
					                if (isOperational) {
 | 
				
			||||||
                    iconName = "pump.svg"
 | 
					                    iconName = "pump.svg"
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                        iconName = "pump_broken.svg"
 | 
					                    iconName = "broken_pump.svg"
 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                if (!self.pump.matchesProperties(properties)) {
 | 
					 | 
				
			||||||
                    iconName = "repair_station.svg"
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    iconName = "repair_station.svg"
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const iconUrl = `./assets/bike/${iconName}`
 | 
					            const iconUrl = `./assets/bike/${iconName}`
 | 
				
			||||||
            return {
 | 
					            return {
 | 
				
			||||||
                color: "#00bb00",
 | 
					                color: "#00bb00",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ export class DrinkingWater extends LayerDefinition {
 | 
				
			||||||
            new Tag("amenity", "drinking_water"),
 | 
					            new Tag("amenity", "drinking_water"),
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        this.maxAllowedOverlapPercentage = 10;
 | 
					        this.maxAllowedOverlapPercentage = 10;
 | 
				
			||||||
 | 
					        this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.minzoom = 13;
 | 
					        this.minzoom = 13;
 | 
				
			||||||
        this.style = this.generateStyleFunction();
 | 
					        this.style = this.generateStyleFunction();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,13 @@ export class NatureReserves extends LayerDefinition {
 | 
				
			||||||
        this.style = this.generateStyleFunction();
 | 
					        this.style = this.generateStyleFunction();
 | 
				
			||||||
        this.elementsToShow = [
 | 
					        this.elementsToShow = [
 | 
				
			||||||
            new ImageCarouselWithUploadConstructor(),
 | 
					            new ImageCarouselWithUploadConstructor(),
 | 
				
			||||||
 | 
					            new TagRenderingOptions({
 | 
				
			||||||
 | 
					                freeform: {
 | 
				
			||||||
 | 
					                    key: "_surface",
 | 
				
			||||||
 | 
					                    renderTemplate: "{_surface}m²",
 | 
				
			||||||
 | 
					                    template: "$$$"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
            new NameQuestion(),
 | 
					            new NameQuestion(),
 | 
				
			||||||
            new AccessTag(),
 | 
					            new AccessTag(),
 | 
				
			||||||
            new OperatorTag(),
 | 
					            new OperatorTag(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,8 @@ import {Layout} from "../Layout";
 | 
				
			||||||
import BikeParkings from "../Layers/BikeParkings";
 | 
					import BikeParkings from "../Layers/BikeParkings";
 | 
				
			||||||
import BikeServices from "../Layers/BikeStations";
 | 
					import BikeServices from "../Layers/BikeStations";
 | 
				
			||||||
import BikeShops from "../Layers/BikeShops";
 | 
					import BikeShops from "../Layers/BikeShops";
 | 
				
			||||||
import {GhostBike} from "../Layers/GhostBike";
 | 
					 | 
				
			||||||
import Translations from "../../UI/i18n/Translations";
 | 
					import Translations from "../../UI/i18n/Translations";
 | 
				
			||||||
import {DrinkingWater} from "../Layers/DrinkingWater";
 | 
					import {DrinkingWater} from "../Layers/DrinkingWater";
 | 
				
			||||||
import {BikeShop} from "../Layers/BikeShop"
 | 
					 | 
				
			||||||
import Combine from "../../UI/Base/Combine";
 | 
					import Combine from "../../UI/Base/Combine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +13,7 @@ export default class Cyclofix extends Layout {
 | 
				
			||||||
            "pomp",
 | 
					            "pomp",
 | 
				
			||||||
            ["en", "nl", "fr"],
 | 
					            ["en", "nl", "fr"],
 | 
				
			||||||
            Translations.t.cyclofix.title,
 | 
					            Translations.t.cyclofix.title,
 | 
				
			||||||
            [new BikeServices(), new BikeShop(), new DrinkingWater(), new BikeParkings()],
 | 
					            [new BikeServices(), new BikeShops(), new DrinkingWater(), new BikeParkings()],
 | 
				
			||||||
            16,
 | 
					            16,
 | 
				
			||||||
            50.8465573,
 | 
					            50.8465573,
 | 
				
			||||||
            4.3516970,
 | 
					            4.3516970,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,9 +11,9 @@ export default class ParkingOperator extends TagRenderingOptions {
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question.Render(),
 | 
				
			||||||
            freeform: {
 | 
					            freeform: {
 | 
				
			||||||
                key: "operator",
 | 
					                key: "operator",
 | 
				
			||||||
                template: to.template.txt,
 | 
					                template: to.template,
 | 
				
			||||||
                renderTemplate: to.render.txt,
 | 
					                renderTemplate: to.render,
 | 
				
			||||||
                placeholder: Translations.t.cyclofix.freeFormPlaceholder.txt
 | 
					                placeholder: Translations.t.cyclofix.freeFormPlaceholder
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag("operator", "KU Leuven"), txt: "KU Leuven"},
 | 
					                {k: new Tag("operator", "KU Leuven"), txt: "KU Leuven"},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,10 +8,10 @@ export default class PumpManual extends TagRenderingOptions {
 | 
				
			||||||
        const to = Translations.t.cyclofix.station.electric
 | 
					        const to = Translations.t.cyclofix.station.electric
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            priority: 5,
 | 
					            priority: 5,
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag("manual", "yes"), txt: to.manual.Render()},
 | 
					                {k: new Tag("manual", "yes"), txt: to.manual},
 | 
				
			||||||
                {k: new Tag("manual", "no"), txt: to.electric.Render()}
 | 
					                {k: new Tag("manual", "no"), txt: to.electric}
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,10 +7,10 @@ export default class PumpOperational extends TagRenderingOptions {
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        const to = Translations.t.cyclofix.station.operational
 | 
					        const to = Translations.t.cyclofix.station.operational
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag("service:bicycle:pump:operational_status","broken"), txt: to.broken.txt},
 | 
					                {k: new Tag("service:bicycle:pump:operational_status","broken"), txt: to.broken},
 | 
				
			||||||
                {k: new Tag("service:bicycle:pump:operational_status",""), txt: to.operational.txt}
 | 
					                {k: new Tag("service:bicycle:pump:operational_status",""), txt: to.operational}
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,21 +7,21 @@ export default class PumpValves extends TagRenderingOptions{
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        const to = Translations.t.cyclofix.station.valves
 | 
					        const to = Translations.t.cyclofix.station.valves
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    k: new Tag("valves", " sclaverand;schrader;dunlop"),
 | 
					                    k: new Tag("valves", " sclaverand;schrader;dunlop"),
 | 
				
			||||||
                    txt: to.default.Render()
 | 
					                    txt: to.default
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                {k: new Tag("valves", "dunlop"), txt: to.dunlop.Render()},
 | 
					                {k: new Tag("valves", "dunlop"), txt: to.dunlop},
 | 
				
			||||||
                {k: new Tag("valves", "sclaverand"), txt: to.sclaverand.Render()},
 | 
					                {k: new Tag("valves", "sclaverand"), txt: to.sclaverand},
 | 
				
			||||||
                {k: new Tag("valves", "auto"), txt: to.auto.Render()},
 | 
					                {k: new Tag("valves", "auto"), txt: to.auto},
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            freeform: {
 | 
					            freeform: {
 | 
				
			||||||
                extraTags: new Tag("fixme", "Freeform valves= tag used: possibly a wrong value"),
 | 
					                extraTags: new Tag("fixme", "Freeform valves= tag used: possibly a wrong value"),
 | 
				
			||||||
                key: "valves",
 | 
					                key: "valves",
 | 
				
			||||||
                template: to.template.txt,
 | 
					                template: to.template,
 | 
				
			||||||
                renderTemplate: to.render.txt
 | 
					                renderTemplate: to.render
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,13 +6,13 @@ import Translations from "../../../UI/i18n/Translations";
 | 
				
			||||||
export default class ShopPump extends TagRenderingOptions {
 | 
					export default class ShopPump extends TagRenderingOptions {
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        const key = 'service:bicycle:diy'
 | 
					        const key = 'service:bicycle:diy'
 | 
				
			||||||
        const to = Translations.t.cylofix.shop.diy
 | 
					        const to = Translations.t.cyclofix.shop.diy
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            priority: 5,
 | 
					            priority: 5,
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag(key, "yes"), txt: to.yes.Render()},
 | 
					                {k: new Tag(key, "yes"), txt: to.yes},
 | 
				
			||||||
                {k: new Tag(key, "no"), txt: to.no.Render()},
 | 
					                {k: new Tag(key, "no"), txt: to.no},
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,14 +4,14 @@ import Translations from "../../../UI/i18n/Translations";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class ShopPump extends TagRenderingOptions {
 | 
					export default class ShopPump extends TagRenderingOptions {
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        const to = Translations.t.cylofix.shop.qName
 | 
					        const to = Translations.t.cyclofix.shop.qName
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            priority: 5,
 | 
					            priority: 5,
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            freeform: {
 | 
					            freeform: {
 | 
				
			||||||
                key: "name",
 | 
					                key: "name",
 | 
				
			||||||
                renderTemplate: to.render.txt,
 | 
					                renderTemplate: to.render,
 | 
				
			||||||
                template: to.template.txt
 | 
					                template: to.template
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,10 +9,10 @@ export default class ShopPump extends TagRenderingOptions {
 | 
				
			||||||
        const to = Translations.t.cyclofix.shop.pump
 | 
					        const to = Translations.t.cyclofix.shop.pump
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            priority: 5,
 | 
					            priority: 5,
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag(key, "yes"), txt: to.yes.Render()},
 | 
					                {k: new Tag(key, "yes"), txt: to.yes},
 | 
				
			||||||
                {k: new Tag(key, "no"), txt: to.no.Render()},
 | 
					                {k: new Tag(key, "no"), txt: to.no},
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,10 +9,10 @@ export default class ShopRental extends TagRenderingOptions {
 | 
				
			||||||
        const to = Translations.t.cyclofix.shop.rental
 | 
					        const to = Translations.t.cyclofix.shop.rental
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            priority: 5,
 | 
					            priority: 5,
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag(key, "yes"), txt: to.yes.Render()},
 | 
					                {k: new Tag(key, "yes"), txt: to.yes},
 | 
				
			||||||
                {k: new Tag(key, "no"), txt: to.no.Render()},
 | 
					                {k: new Tag(key, "no"), txt: to.no},
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,12 +9,12 @@ export default class ShopRepair extends TagRenderingOptions {
 | 
				
			||||||
        const to = Translations.t.cyclofix.shop.repair
 | 
					        const to = Translations.t.cyclofix.shop.repair
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            priority: 5,
 | 
					            priority: 5,
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag(key, "yes"), txt: to.yes.Render()},
 | 
					                {k: new Tag(key, "yes"), txt: to.yes},
 | 
				
			||||||
                {k: new Tag(key, "only_sold"), txt: to.sold.Render()},
 | 
					                {k: new Tag(key, "only_sold"), txt: to.sold},
 | 
				
			||||||
                {k: new Tag(key, "brand"), txt: to.brand.Render()},
 | 
					                {k: new Tag(key, "brand"), txt: to.brand},
 | 
				
			||||||
                {k: new Tag(key, "no"), txt: to.no.Render()},
 | 
					                {k: new Tag(key, "no"), txt: to.no},
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,14 +6,14 @@ import Translations from "../../../UI/i18n/Translations";
 | 
				
			||||||
export default class ShopPump extends TagRenderingOptions {
 | 
					export default class ShopPump extends TagRenderingOptions {
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        const key = 'service:bicycle:second_hand'
 | 
					        const key = 'service:bicycle:second_hand'
 | 
				
			||||||
        const to = Translations.t.cylofix.shop.secondHand
 | 
					        const to = Translations.t.cyclofix.shop.secondHand
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            priority: 5,
 | 
					            priority: 5,
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag(key, "yes"), txt: to.yes.Render()},
 | 
					                {k: new Tag(key, "yes"), txt: to.yes},
 | 
				
			||||||
                {k: new Tag(key, "no"), txt: to.no.Render()},
 | 
					                {k: new Tag(key, "no"), txt: to.no},
 | 
				
			||||||
                {k: new Tag(key, "only"), txt: to.only.Render()},
 | 
					                {k: new Tag(key, "only"), txt: to.only},
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,10 +8,10 @@ export default class StationChain extends TagRenderingOptions {
 | 
				
			||||||
        const to = Translations.t.cyclofix.station.chain
 | 
					        const to = Translations.t.cyclofix.station.chain
 | 
				
			||||||
        super({
 | 
					        super({
 | 
				
			||||||
            priority: 5,
 | 
					            priority: 5,
 | 
				
			||||||
            question: to.question.Render(),
 | 
					            question: to.question,
 | 
				
			||||||
            mappings: [
 | 
					            mappings: [
 | 
				
			||||||
                {k: new Tag("service:bicycle:chain_tool", "yes"), txt: to.yes.Render()},
 | 
					                {k: new Tag("service:bicycle:chain_tool", "yes"), txt: to.yes},
 | 
				
			||||||
                {k: new Tag("service:bicycle:chain_tool", "no"), txt: to.no.Render()},
 | 
					                {k: new Tag("service:bicycle:chain_tool", "no"), txt: to.no},
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,8 +18,8 @@ export default class BikeStationOperator extends TagRenderingOptions {
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            freeform: {
 | 
					            freeform: {
 | 
				
			||||||
                key: "operator",
 | 
					                key: "operator",
 | 
				
			||||||
                template: to.template.txt,
 | 
					                template: to.template,
 | 
				
			||||||
                renderTemplate: to.render.txt,
 | 
					                renderTemplate: to.render,
 | 
				
			||||||
                placeholder: "organisatie"
 | 
					                placeholder: "organisatie"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,8 +28,8 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
 | 
				
			||||||
        freeform?: {
 | 
					        freeform?: {
 | 
				
			||||||
            key: string;
 | 
					            key: string;
 | 
				
			||||||
            tagsPreprocessor?: (tags: any) => any;
 | 
					            tagsPreprocessor?: (tags: any) => any;
 | 
				
			||||||
            template: string;
 | 
					            template: string | UIElement;
 | 
				
			||||||
            renderTemplate: string;
 | 
					            renderTemplate: string | UIElement;
 | 
				
			||||||
            placeholder?: string | UIElement;
 | 
					            placeholder?: string | UIElement;
 | 
				
			||||||
            extraTags?: TagsFilter
 | 
					            extraTags?: TagsFilter
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
| 
						 | 
					@ -77,8 +77,9 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
 | 
				
			||||||
         * In the question, it'll offer a textfield
 | 
					         * In the question, it'll offer a textfield
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        freeform?: {
 | 
					        freeform?: {
 | 
				
			||||||
            key: string, template: string,
 | 
					            key: string,
 | 
				
			||||||
            renderTemplate: string
 | 
					            template: string | UIElement,
 | 
				
			||||||
 | 
					            renderTemplate: string | UIElement
 | 
				
			||||||
            placeholder?: string | UIElement,
 | 
					            placeholder?: string | UIElement,
 | 
				
			||||||
            extraTags?: TagsFilter,
 | 
					            extraTags?: TagsFilter,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -141,14 +142,13 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private _question: UIElement;
 | 
					    private _question: UIElement;
 | 
				
			||||||
    private _mapping: { k: TagsFilter, txt: UIElement, priority?: number }[];
 | 
					    private _mapping: { k: TagsFilter, txt: string | UIElement, priority?: number }[];
 | 
				
			||||||
    private _renderMapping: { k: TagsFilter, txt: UIElement, priority?: number }[];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private _tagsPreprocessor?: ((tags: any) => any);
 | 
					    private _tagsPreprocessor?: ((tags: any) => any);
 | 
				
			||||||
    private _freeform: {
 | 
					    private _freeform: {
 | 
				
			||||||
        key: string, template: string,
 | 
					        key: string, 
 | 
				
			||||||
        renderTemplate: string,
 | 
					        template: string | UIElement,
 | 
				
			||||||
 | 
					        renderTemplate: string | UIElement,
 | 
				
			||||||
        placeholder?: string | UIElement,
 | 
					        placeholder?: string | UIElement,
 | 
				
			||||||
        extraTags?: TagsFilter
 | 
					        extraTags?: TagsFilter
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					@ -171,8 +171,9 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
        question?: string | UIElement,
 | 
					        question?: string | UIElement,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        freeform?: {
 | 
					        freeform?: {
 | 
				
			||||||
            key: string, template: string,
 | 
					            key: string, 
 | 
				
			||||||
            renderTemplate: string
 | 
					            template: string | UIElement,
 | 
				
			||||||
 | 
					            renderTemplate: string | UIElement,
 | 
				
			||||||
            placeholder?: string | UIElement,
 | 
					            placeholder?: string | UIElement,
 | 
				
			||||||
            extraTags?: TagsFilter,
 | 
					            extraTags?: TagsFilter,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -205,14 +206,13 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        this._mapping = [];
 | 
					        this._mapping = [];
 | 
				
			||||||
        this._renderMapping = [];
 | 
					 | 
				
			||||||
        this._freeform = options.freeform;
 | 
					        this._freeform = options.freeform;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const choice of options.mappings ?? []) {
 | 
					        for (const choice of options.mappings ?? []) {
 | 
				
			||||||
            let choiceSubbed = {
 | 
					            let choiceSubbed = {
 | 
				
			||||||
                k: choice.k,
 | 
					                k: choice.k,
 | 
				
			||||||
                txt: this.ApplyTemplate(choice.txt),
 | 
					                txt: choice.txt,
 | 
				
			||||||
                priority: choice.priority
 | 
					                priority: choice.priority
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,7 +220,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
                choiceSubbed = {
 | 
					                choiceSubbed = {
 | 
				
			||||||
                    k: choice.k.substituteValues(
 | 
					                    k: choice.k.substituteValues(
 | 
				
			||||||
                        options.tagsPreprocessor(this._source.data)),
 | 
					                        options.tagsPreprocessor(this._source.data)),
 | 
				
			||||||
                    txt: this.ApplyTemplate(choice.txt),
 | 
					                    txt: choice.txt,
 | 
				
			||||||
                    priority: choice.priority
 | 
					                    priority: choice.priority
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -270,7 +270,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                return "<span class='skip-button'>"+Translations.t.general.skip.R()+"</span>";
 | 
					                return "<span class='skip-button'>"+Translations.t.general.skip.R()+"</span>";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        }, [Locale.language]);
 | 
				
			||||||
        // And at last, set up the skip button
 | 
					        // And at last, set up the skip button
 | 
				
			||||||
        this._skipButton = new VariableUiElement(cancelContents).onClick(cancel)    ;
 | 
					        this._skipButton = new VariableUiElement(cancelContents).onClick(cancel)    ;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -278,8 +278,9 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private InputElementFor(options: {
 | 
					    private InputElementFor(options: {
 | 
				
			||||||
        freeform?: {
 | 
					        freeform?: {
 | 
				
			||||||
            key: string, template: string,
 | 
					            key: string, 
 | 
				
			||||||
            renderTemplate: string
 | 
					            template: string | UIElement,
 | 
				
			||||||
 | 
					            renderTemplate: string | UIElement,
 | 
				
			||||||
            placeholder?: string | UIElement,
 | 
					            placeholder?: string | UIElement,
 | 
				
			||||||
            extraTags?: TagsFilter,
 | 
					            extraTags?: TagsFilter,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -368,7 +369,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
            toString: toString
 | 
					            toString: toString
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const prepost = freeform.template.split("$$$");
 | 
					        const prepost = Translations.W(freeform.template).InnerRender().split("$$$");
 | 
				
			||||||
        return new InputElementWrapper(prepost[0], textField, prepost[1]);
 | 
					        return new InputElementWrapper(prepost[0], textField, prepost[1]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -376,7 +377,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
    IsKnown(): boolean {
 | 
					    IsKnown(): boolean {
 | 
				
			||||||
        const tags = TagUtils.proprtiesToKV(this._source.data);
 | 
					        const tags = TagUtils.proprtiesToKV(this._source.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const oneOnOneElement of this._mapping.concat(this._renderMapping)) {
 | 
					        for (const oneOnOneElement of this._mapping) {
 | 
				
			||||||
            if (oneOnOneElement.k === null || oneOnOneElement.k.matches(tags)) {
 | 
					            if (oneOnOneElement.k === null || oneOnOneElement.k.matches(tags)) {
 | 
				
			||||||
                return true;
 | 
					                return true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -386,10 +387,9 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private CurrentValue(): TagsFilter {
 | 
					    private CurrentValue(): TagsFilter {
 | 
				
			||||||
        console.log("Creating a current value...")
 | 
					 | 
				
			||||||
        const tags = TagUtils.proprtiesToKV(this._source.data);
 | 
					        const tags = TagUtils.proprtiesToKV(this._source.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const oneOnOneElement of this._mapping.concat(this._renderMapping)) {
 | 
					        for (const oneOnOneElement of this._mapping) {
 | 
				
			||||||
            if (oneOnOneElement.k !== null && oneOnOneElement.k.matches(tags)) {
 | 
					            if (oneOnOneElement.k !== null && oneOnOneElement.k.matches(tags)) {
 | 
				
			||||||
                return oneOnOneElement.k;
 | 
					                return oneOnOneElement.k;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -398,7 +398,6 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
            return undefined;
 | 
					            return undefined;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        console.log("Got a freeform tag:", new Tag(this._freeform.key, this._source.data[this._freeform.key]))
 | 
					 | 
				
			||||||
        return new Tag(this._freeform.key, this._source.data[this._freeform.key]);
 | 
					        return new Tag(this._freeform.key, this._source.data[this._freeform.key]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -431,7 +430,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let highestScore = -100;
 | 
					        let highestScore = -100;
 | 
				
			||||||
        let highestTemplate = undefined;
 | 
					        let highestTemplate = undefined;
 | 
				
			||||||
        for (const oneOnOneElement of this._mapping.concat(this._renderMapping)) {
 | 
					        for (const oneOnOneElement of this._mapping) {
 | 
				
			||||||
            if (oneOnOneElement.k == null ||
 | 
					            if (oneOnOneElement.k == null ||
 | 
				
			||||||
                oneOnOneElement.k.matches(tags)) {
 | 
					                oneOnOneElement.k.matches(tags)) {
 | 
				
			||||||
                // We have found a matching key -> we use the template, but only if it scores better
 | 
					                // We have found a matching key -> we use the template, but only if it scores better
 | 
				
			||||||
| 
						 | 
					@ -457,7 +456,6 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    InnerRender(): string {
 | 
					    InnerRender(): string {
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (this.IsQuestioning() || this._editMode.data) {
 | 
					        if (this.IsQuestioning() || this._editMode.data) {
 | 
				
			||||||
            // Not yet known or questioning, we have to ask a question
 | 
					            // Not yet known or questioning, we have to ask a question
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -499,10 +497,13 @@ class TagRendering extends UIElement implements TagDependantUIElement {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ApplyTemplate(template: string | UIElement): UIElement {
 | 
					    private ApplyTemplate(template: string | UIElement): UIElement {
 | 
				
			||||||
        if (template instanceof UIElement) {
 | 
					        if(template === undefined || template === null){
 | 
				
			||||||
            return template;
 | 
					            throw "Trying to apply a template, but the template is null/undefined"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const tags = this._tagsPreprocessor(this._source.data);
 | 
					        const tags = this._tagsPreprocessor(this._source.data);
 | 
				
			||||||
 | 
					        if (template instanceof UIElement) {
 | 
				
			||||||
 | 
					            template = template.Render();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return new FixedUiElement(TagUtils.ApplyTemplate(template, tags));
 | 
					        return new FixedUiElement(TagUtils.ApplyTemplate(template, tags));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import { Changes } from "./Changes";
 | 
				
			||||||
import L from "leaflet"
 | 
					import L from "leaflet"
 | 
				
			||||||
import { GeoOperations } from "./GeoOperations";
 | 
					import { GeoOperations } from "./GeoOperations";
 | 
				
			||||||
import { UIElement } from "../UI/UIElement";
 | 
					import { UIElement } from "../UI/UIElement";
 | 
				
			||||||
 | 
					import {LayerDefinition} from "../Customizations/LayerDefinition";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***
 | 
					/***
 | 
				
			||||||
 * A filtered layer is a layer which offers a 'set-data' function
 | 
					 * A filtered layer is a layer which offers a 'set-data' function
 | 
				
			||||||
| 
						 | 
					@ -18,7 +19,7 @@ import { UIElement } from "../UI/UIElement";
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export class FilteredLayer {
 | 
					export class FilteredLayer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public readonly name: string;
 | 
					    public readonly name: string | UIElement;
 | 
				
			||||||
    public readonly filters: TagsFilter;
 | 
					    public readonly filters: TagsFilter;
 | 
				
			||||||
    public readonly isDisplayed: UIEventSource<boolean> = new UIEventSource(true);
 | 
					    public readonly isDisplayed: UIEventSource<boolean> = new UIEventSource(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +33,7 @@ export class FilteredLayer {
 | 
				
			||||||
    /** The featurecollection from overpass
 | 
					    /** The featurecollection from overpass
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private _dataFromOverpass;
 | 
					    private _dataFromOverpass;
 | 
				
			||||||
 | 
					    private _wayHandling: number;
 | 
				
			||||||
    /** List of new elements, geojson features
 | 
					    /** List of new elements, geojson features
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private _newElements = [];
 | 
					    private _newElements = [];
 | 
				
			||||||
| 
						 | 
					@ -39,19 +41,21 @@ export class FilteredLayer {
 | 
				
			||||||
     * The leaflet layer object which should be removed on rerendering
 | 
					     * The leaflet layer object which should be removed on rerendering
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private _geolayer;
 | 
					    private _geolayer;
 | 
				
			||||||
    private _selectedElement: UIEventSource<any>;
 | 
					    private _selectedElement: UIEventSource<{feature: any}>;
 | 
				
			||||||
    private _showOnPopup: (tags: UIEventSource<any>) => UIElement;
 | 
					    private _showOnPopup: (tags: UIEventSource<any>, feature: any) => UIElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(
 | 
					    constructor(
 | 
				
			||||||
        name: string,
 | 
					        name: string | UIElement,
 | 
				
			||||||
        map: Basemap, storage: ElementStorage,
 | 
					        map: Basemap, storage: ElementStorage,
 | 
				
			||||||
        changes: Changes,
 | 
					        changes: Changes,
 | 
				
			||||||
        filters: TagsFilter,
 | 
					        filters: TagsFilter,
 | 
				
			||||||
        maxAllowedOverlap: number,
 | 
					        maxAllowedOverlap: number,
 | 
				
			||||||
 | 
					        wayHandling: number,
 | 
				
			||||||
        style: ((properties) => any),
 | 
					        style: ((properties) => any),
 | 
				
			||||||
        selectedElement: UIEventSource<any>,
 | 
					        selectedElement: UIEventSource<{feature: any}>,
 | 
				
			||||||
        showOnPopup: ((tags: UIEventSource<any>) => UIElement)
 | 
					        showOnPopup: ((tags: UIEventSource<any>, feature: any) => UIElement)
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
 | 
					        this._wayHandling = wayHandling;
 | 
				
			||||||
        this._selectedElement = selectedElement;
 | 
					        this._selectedElement = selectedElement;
 | 
				
			||||||
        this._showOnPopup = showOnPopup;
 | 
					        this._showOnPopup = showOnPopup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,6 +70,7 @@ export class FilteredLayer {
 | 
				
			||||||
        this._style = style;
 | 
					        this._style = style;
 | 
				
			||||||
        this._storage = storage;
 | 
					        this._storage = storage;
 | 
				
			||||||
        this._maxAllowedOverlap = maxAllowedOverlap;
 | 
					        this._maxAllowedOverlap = maxAllowedOverlap;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        const self = this;
 | 
					        const self = this;
 | 
				
			||||||
        this.isDisplayed.addCallback(function (isDisplayed) {
 | 
					        this.isDisplayed.addCallback(function (isDisplayed) {
 | 
				
			||||||
            if (self._geolayer !== undefined && self._geolayer !== null) {
 | 
					            if (self._geolayer !== undefined && self._geolayer !== null) {
 | 
				
			||||||
| 
						 | 
					@ -86,10 +91,18 @@ export class FilteredLayer {
 | 
				
			||||||
    public SetApplicableData(geojson: any): any {
 | 
					    public SetApplicableData(geojson: any): any {
 | 
				
			||||||
        const leftoverFeatures = [];
 | 
					        const leftoverFeatures = [];
 | 
				
			||||||
        const selfFeatures = [];
 | 
					        const selfFeatures = [];
 | 
				
			||||||
        for (const feature of geojson.features) {
 | 
					        for (let feature of geojson.features) {
 | 
				
			||||||
            // feature.properties contains all the properties
 | 
					            // feature.properties contains all the properties
 | 
				
			||||||
            var tags = TagUtils.proprtiesToKV(feature.properties);
 | 
					            var tags = TagUtils.proprtiesToKV(feature.properties);
 | 
				
			||||||
            if (this.filters.matches(tags)) {
 | 
					            if (this.filters.matches(tags)) {
 | 
				
			||||||
 | 
					                feature.properties["_surface"] = GeoOperations.surfaceAreaInSqMeters(feature);
 | 
				
			||||||
 | 
					                if(feature.geometry.type !== "Point"){
 | 
				
			||||||
 | 
					                    if(this._wayHandling === LayerDefinition.WAYHANDLING_CENTER_AND_WAY){
 | 
				
			||||||
 | 
					                        selfFeatures.push(GeoOperations.centerpoint(feature));
 | 
				
			||||||
 | 
					                    }else if(this._wayHandling === LayerDefinition.WAYHANDLING_CENTER_ONLY){
 | 
				
			||||||
 | 
					                        feature = GeoOperations.centerpoint(feature);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                selfFeatures.push(feature);
 | 
					                selfFeatures.push(feature);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                leftoverFeatures.push(feature);
 | 
					                leftoverFeatures.push(feature);
 | 
				
			||||||
| 
						 | 
					@ -201,8 +214,8 @@ export class FilteredLayer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                layer.on("click", function (e) {
 | 
					                layer.on("click", function (e) {
 | 
				
			||||||
                    console.log("Selected ", feature)
 | 
					                    console.log("Selected ", feature)
 | 
				
			||||||
                    self._selectedElement.setData(feature.properties);
 | 
					                    self._selectedElement.setData({feature: feature});
 | 
				
			||||||
                    const uiElement = self._showOnPopup(eventSource);
 | 
					                    const uiElement = self._showOnPopup(eventSource, feature);
 | 
				
			||||||
                    const popup = L.popup()
 | 
					                    const popup = L.popup()
 | 
				
			||||||
                        .setContent(uiElement.Render())
 | 
					                        .setContent(uiElement.Render())
 | 
				
			||||||
                        .setLatLng(e.latlng)
 | 
					                        .setLatLng(e.latlng)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,15 @@ export class GeoOperations {
 | 
				
			||||||
        return turf.area(feature);
 | 
					        return turf.area(feature);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static centerpoint(feature: any) 
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const newFeature= turf.center(feature);    
 | 
				
			||||||
 | 
					        newFeature.properties = feature.properties;
 | 
				
			||||||
 | 
					        newFeature.id = feature.id;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return newFeature;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static featureIsContainedInAny(feature: any,
 | 
					    static featureIsContainedInAny(feature: any,
 | 
				
			||||||
                                   shouldNotContain: any[],
 | 
					                                   shouldNotContain: any[],
 | 
				
			||||||
                                   maxOverlapPercentage: number): boolean {
 | 
					                                   maxOverlapPercentage: number): boolean {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ export class Imgur {
 | 
				
			||||||
        title: string, description: string, blobs: FileList,
 | 
					        title: string, description: string, blobs: FileList,
 | 
				
			||||||
        handleSuccessfullUpload: ((imageURL: string) => void),
 | 
					        handleSuccessfullUpload: ((imageURL: string) => void),
 | 
				
			||||||
        allDone: (() => void),
 | 
					        allDone: (() => void),
 | 
				
			||||||
 | 
					        onFail: ((reason: string) => void),
 | 
				
			||||||
        offset:number = 0) {
 | 
					        offset:number = 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (blobs.length == offset) {
 | 
					        if (blobs.length == offset) {
 | 
				
			||||||
| 
						 | 
					@ -24,7 +25,8 @@ export class Imgur {
 | 
				
			||||||
                    handleSuccessfullUpload,
 | 
					                    handleSuccessfullUpload,
 | 
				
			||||||
                    allDone,
 | 
					                    allDone,
 | 
				
			||||||
                    offset + 1);
 | 
					                    offset + 1);
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
 | 
					            onFail
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,7 +76,8 @@ export class Imgur {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static uploadImage(title: string, description: string, blob,
 | 
					    static uploadImage(title: string, description: string, blob,
 | 
				
			||||||
                       handleSuccessfullUpload: ((imageURL: string) => void)) {
 | 
					                       handleSuccessfullUpload: ((imageURL: string) => void),
 | 
				
			||||||
 | 
					                       onFail: (reason:string) => void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const apiUrl = 'https://api.imgur.com/3/image';
 | 
					        const apiUrl = 'https://api.imgur.com/3/image';
 | 
				
			||||||
        const apiKey = '7070e7167f0a25a';
 | 
					        const apiKey = '7070e7167f0a25a';
 | 
				
			||||||
| 
						 | 
					@ -105,7 +108,8 @@ export class Imgur {
 | 
				
			||||||
            response = JSON.parse(response);
 | 
					            response = JSON.parse(response);
 | 
				
			||||||
            handleSuccessfullUpload(response.data.link);
 | 
					            handleSuccessfullUpload(response.data.link);
 | 
				
			||||||
        }).fail((reason) => {
 | 
					        }).fail((reason) => {
 | 
				
			||||||
            console.log("Uploading to IMGUR failed", reason)
 | 
					            console.log("Uploading to IMGUR failed", reason);
 | 
				
			||||||
 | 
					            onFail(reason)
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,6 @@ export class UserDetails {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class OsmConnection {
 | 
					export class OsmConnection {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private auth = new osmAuth({
 | 
					    private auth = new osmAuth({
 | 
				
			||||||
        oauth_consumer_key: 'hivV7ec2o49Two8g9h8Is1VIiVOgxQ1iYexCbvem',
 | 
					        oauth_consumer_key: 'hivV7ec2o49Two8g9h8Is1VIiVOgxQ1iYexCbvem',
 | 
				
			||||||
        oauth_secret: 'wDBRTCem0vxD7txrg1y6p5r8nvmz8tAhET7zDASI',
 | 
					        oauth_secret: 'wDBRTCem0vxD7txrg1y6p5r8nvmz8tAhET7zDASI',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,12 +48,18 @@ export class OsmImageUploadHandler {
 | 
				
			||||||
            title: title,
 | 
					            title: title,
 | 
				
			||||||
            description: description,
 | 
					            description: description,
 | 
				
			||||||
            handleURL: function (url) {
 | 
					            handleURL: function (url) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let key = "image";
 | 
				
			||||||
 | 
					                if (tags["image"] !== undefined) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    let freeIndex = 0;
 | 
					                    let freeIndex = 0;
 | 
				
			||||||
                    while (tags["image:" + freeIndex] !== undefined) {
 | 
					                    while (tags["image:" + freeIndex] !== undefined) {
 | 
				
			||||||
                        freeIndex++;
 | 
					                        freeIndex++;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                console.log("Adding image:" + freeIndex, url);
 | 
					                    key = "image:" + freeIndex;
 | 
				
			||||||
                changes.addChange(tags.id, "image:" + freeIndex, url);
 | 
					                }
 | 
				
			||||||
 | 
					                console.log("Adding image:" + key, url);
 | 
				
			||||||
 | 
					                changes.addChange(tags.id, key, url);
 | 
				
			||||||
                self._slideShow.MoveTo(-1); // set the last (thus newly added) image) to view
 | 
					                self._slideShow.MoveTo(-1); // set the last (thus newly added) image) to view
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            allDone: function () {
 | 
					            allDone: function () {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ export class StrayClickHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(
 | 
					    constructor(
 | 
				
			||||||
        basemap: Basemap,
 | 
					        basemap: Basemap,
 | 
				
			||||||
        selectElement: UIEventSource<any>,
 | 
					        selectElement: UIEventSource<{ feature: any }>,
 | 
				
			||||||
        fullScreenMessage: UIEventSource<UIElement>, 
 | 
					        fullScreenMessage: UIEventSource<UIElement>, 
 | 
				
			||||||
        uiToShow: (() => UIElement)) {
 | 
					        uiToShow: (() => UIElement)) {
 | 
				
			||||||
        this._basemap = basemap;
 | 
					        this._basemap = basemap;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,9 @@ When a map feature is clicked, a popup shows the information, images and questio
 | 
				
			||||||
The answers given by the user are sent (after a few seconds) to OpenStreetMap directly - if the user is logged in. If not logged in, the user is prompted to do so. 
 | 
					The answers given by the user are sent (after a few seconds) to OpenStreetMap directly - if the user is logged in. If not logged in, the user is prompted to do so. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The UI-event-source is a class where the entire system is built upon, it acts as an observable object: another object can register for changes to update when needed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Searching images
 | 
					### Searching images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Images are fetched from:
 | 
					Images are fetched from:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,11 +41,11 @@ export class CenterMessageBox extends UIElement {
 | 
				
			||||||
            return this._centermessage.data;
 | 
					            return this._centermessage.data;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (this._queryRunning.data) {
 | 
					        if (this._queryRunning.data) {
 | 
				
			||||||
            return Translations.t.centerMessage.loadingData.txt;
 | 
					            return Translations.t.centerMessage.loadingData.Render();
 | 
				
			||||||
        } else if (this._zoomInMore.data) {
 | 
					        } else if (this._zoomInMore.data) {
 | 
				
			||||||
            return Translations.t.centerMessage.zoomIn.txt;
 | 
					            return Translations.t.centerMessage.zoomIn.Render();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return Translations.t.centerMessage.ready.txt;
 | 
					        return Translations.t.centerMessage.ready.Render();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,9 +11,17 @@ import {OsmLink} from "../Customizations/Questions/OsmLink";
 | 
				
			||||||
import {WikipediaLink} from "../Customizations/Questions/WikipediaLink";
 | 
					import {WikipediaLink} from "../Customizations/Questions/WikipediaLink";
 | 
				
			||||||
import {And} from "../Logic/TagsFilter";
 | 
					import {And} from "../Logic/TagsFilter";
 | 
				
			||||||
import {TagDependantUIElement, TagDependantUIElementConstructor} from "../Customizations/UIElementConstructor";
 | 
					import {TagDependantUIElement, TagDependantUIElementConstructor} from "../Customizations/UIElementConstructor";
 | 
				
			||||||
 | 
					import Translations from "./i18n/Translations";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class FeatureInfoBox extends UIElement {
 | 
					export class FeatureInfoBox extends UIElement {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The actual GEOJSON-object, with geometry and stuff
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private _feature: any;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The tags, wrapped in a global event source
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private _tagsES: UIEventSource<any>;
 | 
					    private _tagsES: UIEventSource<any>;
 | 
				
			||||||
    private _changes: Changes;
 | 
					    private _changes: Changes;
 | 
				
			||||||
    private _userDetails: UIEventSource<UserDetails>;
 | 
					    private _userDetails: UIEventSource<UserDetails>;
 | 
				
			||||||
| 
						 | 
					@ -24,11 +32,14 @@ export class FeatureInfoBox extends UIElement {
 | 
				
			||||||
    private _wikipedialink: UIElement;
 | 
					    private _wikipedialink: UIElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    private _infoboxes: TagDependantUIElement[];
 | 
					    private _infoboxes: TagDependantUIElement[];
 | 
				
			||||||
    private _questions: QuestionPicker;
 | 
					    private _questions: QuestionPicker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private _oneSkipped = Translations.t.general.oneSkippedQuestion.Clone();
 | 
				
			||||||
 | 
					    private _someSkipped = Translations.t.general.skippedQuestions.Clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(
 | 
					    constructor(
 | 
				
			||||||
 | 
					        feature: any,
 | 
				
			||||||
        tagsES: UIEventSource<any>,
 | 
					        tagsES: UIEventSource<any>,
 | 
				
			||||||
        title: TagRenderingOptions | UIElement,
 | 
					        title: TagRenderingOptions | UIElement,
 | 
				
			||||||
        elementsToShow: TagDependantUIElementConstructor[],
 | 
					        elementsToShow: TagDependantUIElementConstructor[],
 | 
				
			||||||
| 
						 | 
					@ -36,19 +47,34 @@ export class FeatureInfoBox extends UIElement {
 | 
				
			||||||
        userDetails: UIEventSource<UserDetails>
 | 
					        userDetails: UIEventSource<UserDetails>
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        super(tagsES);
 | 
					        super(tagsES);
 | 
				
			||||||
 | 
					        this._feature = feature;
 | 
				
			||||||
        this._tagsES = tagsES;
 | 
					        this._tagsES = tagsES;
 | 
				
			||||||
        this._changes = changes;
 | 
					        this._changes = changes;
 | 
				
			||||||
        this._userDetails = userDetails;
 | 
					        this._userDetails = userDetails;
 | 
				
			||||||
        this.ListenTo(userDetails);
 | 
					        this.ListenTo(userDetails);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const deps = {tags:this._tagsES , changes:this._changes}
 | 
					        const deps = {tags: this._tagsES, changes: this._changes}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._infoboxes = [];
 | 
					        this._infoboxes = [];
 | 
				
			||||||
        elementsToShow = elementsToShow ?? []
 | 
					        elementsToShow = elementsToShow ?? []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const self = this;
 | 
				
			||||||
        for (const tagRenderingOption of elementsToShow) {
 | 
					        for (const tagRenderingOption of elementsToShow) {
 | 
				
			||||||
            this._infoboxes.push(
 | 
					            self._infoboxes.push(
 | 
				
			||||||
                tagRenderingOption.construct(deps));
 | 
					                tagRenderingOption.construct(deps));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        function initTags() {
 | 
				
			||||||
 | 
					            self._infoboxes = []
 | 
				
			||||||
 | 
					            for (const tagRenderingOption of elementsToShow) {
 | 
				
			||||||
 | 
					                self._infoboxes.push(
 | 
				
			||||||
 | 
					                    tagRenderingOption.construct(deps));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            self.Update();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._someSkipped.onClick(initTags)
 | 
				
			||||||
 | 
					        this._oneSkipped.onClick(initTags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        title = title ?? new TagRenderingOptions(
 | 
					        title = title ?? new TagRenderingOptions(
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
| 
						 | 
					@ -71,13 +97,16 @@ export class FeatureInfoBox extends UIElement {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const info = [];
 | 
					        const info = [];
 | 
				
			||||||
        const questions : TagDependantUIElement[] = [];
 | 
					        const questions: TagDependantUIElement[] = [];
 | 
				
			||||||
 | 
					        let skippedQuestions = 0;
 | 
				
			||||||
        for (const infobox of this._infoboxes) {
 | 
					        for (const infobox of this._infoboxes) {
 | 
				
			||||||
            if (infobox.IsKnown()) {
 | 
					            if (infobox.IsKnown()) {
 | 
				
			||||||
                info.push(infobox);
 | 
					                info.push(infobox);
 | 
				
			||||||
            } else if (infobox.IsQuestioning()) {
 | 
					            } else if (infobox.IsQuestioning()) {
 | 
				
			||||||
                questions.push(infobox);
 | 
					                questions.push(infobox);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // This question is neither known nor questioning -> it was skipped
 | 
				
			||||||
 | 
					                skippedQuestions++;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -97,6 +126,10 @@ export class FeatureInfoBox extends UIElement {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            questionsHtml = mostImportantQuestion.Render();
 | 
					            questionsHtml = mostImportantQuestion.Render();
 | 
				
			||||||
 | 
					        } else if (skippedQuestions == 1) {
 | 
				
			||||||
 | 
					            questionsHtml = this._oneSkipped.Render();
 | 
				
			||||||
 | 
					        } else if (skippedQuestions > 0) {
 | 
				
			||||||
 | 
					            questionsHtml = this._someSkipped.Render();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return "<div class='featureinfobox'>" +
 | 
					        return "<div class='featureinfobox'>" +
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,12 +11,13 @@ export class ImageUploadFlow extends UIElement {
 | 
				
			||||||
    private _licensePicker: UIElement;
 | 
					    private _licensePicker: UIElement;
 | 
				
			||||||
    private _selectedLicence: UIEventSource<string>;
 | 
					    private _selectedLicence: UIEventSource<string>;
 | 
				
			||||||
    private _isUploading: UIEventSource<number> = new UIEventSource<number>(0)
 | 
					    private _isUploading: UIEventSource<number> = new UIEventSource<number>(0)
 | 
				
			||||||
 | 
					    private _didFail: UIEventSource<boolean> = new UIEventSource<boolean>(false);
 | 
				
			||||||
    private _uploadOptions: (license: string) => { title: string; description: string; handleURL: (url: string) => void; allDone: (() => void) };
 | 
					    private _uploadOptions: (license: string) => { title: string; description: string; handleURL: (url: string) => void; allDone: (() => void) };
 | 
				
			||||||
    private _userdetails: UIEventSource<UserDetails>;
 | 
					    private _userdetails: UIEventSource<UserDetails>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(
 | 
					    constructor(
 | 
				
			||||||
        userInfo: UIEventSource<UserDetails>,
 | 
					        userInfo: UIEventSource<UserDetails>,
 | 
				
			||||||
        preferedLicense : UIEventSource<string>,
 | 
					        preferedLicense: UIEventSource<string>,
 | 
				
			||||||
        uploadOptions: ((license: string) =>
 | 
					        uploadOptions: ((license: string) =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                title: string,
 | 
					                title: string,
 | 
				
			||||||
| 
						 | 
					@ -30,6 +31,7 @@ export class ImageUploadFlow extends UIElement {
 | 
				
			||||||
        this.ListenTo(userInfo);
 | 
					        this.ListenTo(userInfo);
 | 
				
			||||||
        this._uploadOptions = uploadOptions;
 | 
					        this._uploadOptions = uploadOptions;
 | 
				
			||||||
        this.ListenTo(this._isUploading);
 | 
					        this.ListenTo(this._isUploading);
 | 
				
			||||||
 | 
					        this.ListenTo(this._didFail);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const licensePicker = new DropDown(Translations.t.image.willBePublished,
 | 
					        const licensePicker = new DropDown(Translations.t.image.willBePublished,
 | 
				
			||||||
            [
 | 
					            [
 | 
				
			||||||
| 
						 | 
					@ -60,6 +62,10 @@ export class ImageUploadFlow extends UIElement {
 | 
				
			||||||
            uploadingMessage = "<b>Uploading multiple pictures, " + this._isUploading.data + " left...</b>"
 | 
					            uploadingMessage = "<b>Uploading multiple pictures, " + this._isUploading.data + " left...</b>"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        if(this._didFail.data){
 | 
				
			||||||
 | 
					            uploadingMessage += "<b>Some images failed to upload. Imgur migth be down or you might block third-party API's (e.g. by using Brave or UMatrix)</b><br/>"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return "" +
 | 
					        return "" +
 | 
				
			||||||
            "<div class='imageflow'>" +
 | 
					            "<div class='imageflow'>" +
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,7 +74,7 @@ export class ImageUploadFlow extends UIElement {
 | 
				
			||||||
            "<div class='imageflow-file-input-wrapper'>" +
 | 
					            "<div class='imageflow-file-input-wrapper'>" +
 | 
				
			||||||
            "<img src='./assets/camera-plus.svg' alt='upload image'/> " +
 | 
					            "<img src='./assets/camera-plus.svg' alt='upload image'/> " +
 | 
				
			||||||
            `<span class='imageflow-add-picture'>${Translations.t.image.addPicture.R()}</span>` +
 | 
					            `<span class='imageflow-add-picture'>${Translations.t.image.addPicture.R()}</span>` +
 | 
				
			||||||
            "<div class='break'></div>"+
 | 
					            "<div class='break'></div>" +
 | 
				
			||||||
            "</div>" +
 | 
					            "</div>" +
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this._licensePicker.Render() + "<br/>" +
 | 
					            this._licensePicker.Render() + "<br/>" +
 | 
				
			||||||
| 
						 | 
					@ -116,11 +122,12 @@ export class ImageUploadFlow extends UIElement {
 | 
				
			||||||
                    function () {
 | 
					                    function () {
 | 
				
			||||||
                        console.log("All uploads completed")
 | 
					                        console.log("All uploads completed")
 | 
				
			||||||
                        opts.allDone();
 | 
					                        opts.allDone();
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    function(failReason) {
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -15,17 +15,17 @@ export class SimpleAddUI extends UIElement {
 | 
				
			||||||
    private _addButtons: UIElement[];
 | 
					    private _addButtons: UIElement[];
 | 
				
			||||||
    private _lastClickLocation: UIEventSource<{ lat: number; lon: number }>;
 | 
					    private _lastClickLocation: UIEventSource<{ lat: number; lon: number }>;
 | 
				
			||||||
    private _changes: Changes;
 | 
					    private _changes: Changes;
 | 
				
			||||||
    private _selectedElement: UIEventSource<any>;
 | 
					    private _selectedElement: UIEventSource<{feature: any}>;
 | 
				
			||||||
    private _dataIsLoading: UIEventSource<boolean>;
 | 
					    private _dataIsLoading: UIEventSource<boolean>;
 | 
				
			||||||
    private _userDetails: UIEventSource<UserDetails>;
 | 
					    private _userDetails: UIEventSource<UserDetails>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(zoomlevel: UIEventSource<{ zoom: number }>,
 | 
					    constructor(zoomlevel: UIEventSource<{ zoom: number }>,
 | 
				
			||||||
                lastClickLocation: UIEventSource<{ lat: number, lon: number }>,
 | 
					                lastClickLocation: UIEventSource<{ lat: number, lon: number }>,
 | 
				
			||||||
                changes: Changes,
 | 
					                changes: Changes,
 | 
				
			||||||
                selectedElement: UIEventSource<any>,
 | 
					                selectedElement: UIEventSource<{feature: any}>,
 | 
				
			||||||
                dataIsLoading: UIEventSource<boolean>,
 | 
					                dataIsLoading: UIEventSource<boolean>,
 | 
				
			||||||
                userDetails: UIEventSource<UserDetails>,
 | 
					                userDetails: UIEventSource<UserDetails>,
 | 
				
			||||||
                addButtons: { name: string; icon: string; tags: Tag[]; layerToAddTo: FilteredLayer }[],
 | 
					                addButtons: { name: UIElement; icon: string; tags: Tag[]; layerToAddTo: FilteredLayer }[],
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        super(zoomlevel);
 | 
					        super(zoomlevel);
 | 
				
			||||||
        this._zoomlevel = zoomlevel;
 | 
					        this._zoomlevel = zoomlevel;
 | 
				
			||||||
| 
						 | 
					@ -42,21 +42,20 @@ export class SimpleAddUI extends UIElement {
 | 
				
			||||||
            // <button type='button'> looks SO retarded
 | 
					            // <button type='button'> looks SO retarded
 | 
				
			||||||
            // the default type of button is 'submit', which performs a POST and page reload
 | 
					            // the default type of button is 'submit', which performs a POST and page reload
 | 
				
			||||||
            const button =
 | 
					            const button =
 | 
				
			||||||
                new Button(new FixedUiElement("Add a " + option.name + " here"),
 | 
					                new Button(new FixedUiElement("Add a " + option.name.Render() + " here"),
 | 
				
			||||||
                    this.CreatePoint(option));
 | 
					                    this.CreatePoint(option));
 | 
				
			||||||
            this._addButtons.push(button);
 | 
					            this._addButtons.push(button);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private CreatePoint(option: { name: string; icon: string; tags: Tag[]; layerToAddTo: FilteredLayer }) {
 | 
					    private CreatePoint(option: {icon: string; tags: Tag[]; layerToAddTo: FilteredLayer }) {
 | 
				
			||||||
        const self = this;
 | 
					        const self = this;
 | 
				
			||||||
        return () => {
 | 
					        return () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            console.log("Creating a new ", option.name, " at last click location");
 | 
					 | 
				
			||||||
            const loc = self._lastClickLocation.data;
 | 
					            const loc = self._lastClickLocation.data;
 | 
				
			||||||
            let feature = self._changes.createElement(option.tags, loc.lat, loc.lon);
 | 
					            let feature = self._changes.createElement(option.tags, loc.lat, loc.lon);
 | 
				
			||||||
            option.layerToAddTo.AddNewElement(feature);
 | 
					            option.layerToAddTo.AddNewElement(feature);
 | 
				
			||||||
            self._selectedElement.setData(feature.properties);
 | 
					            self._selectedElement.setData({feature: feature});
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,4 +36,8 @@ export default class Translation extends UIElement {
 | 
				
			||||||
        return new Translation(this.translations).Render();
 | 
					        return new Translation(this.translations).Render();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Clone(){
 | 
				
			||||||
 | 
					        return new Translation(this.translations)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,12 @@ import {FixedUiElement} from "../Base/FixedUiElement";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class Translations {
 | 
					export default class Translations {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        throw "Translations is static. If you want to intitialize a new translation, use the singular form"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static t = {
 | 
					    static t = {
 | 
				
			||||||
        cyclofix: {
 | 
					        cyclofix: {
 | 
				
			||||||
            title: new T({
 | 
					            title: new T({
 | 
				
			||||||
| 
						 | 
					@ -205,8 +211,17 @@ export default class Translations {
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            shop: {
 | 
					            shop: {
 | 
				
			||||||
                name: new T({en: 'bike shop', nl: 'fietswinkel', fr: 'TODO: fr'}),
 | 
					                name: new T({en: 'bike shop', nl: 'fietswinkel', fr: 'TODO: fr'}),
 | 
				
			||||||
                title: new T({en: 'Bike repair/shop', nl: 'Fietswinkel/herstelling', fr: 'TODO: fr'}),
 | 
					                
 | 
				
			||||||
                titleRepair: new T({en: 'Bike shop', nl: 'Fietswinkel', fr: 'TODO: fr'}),
 | 
					                title: new T({en: 'Bike shop', nl: 'Fietszaak', fr: 'TODO: fr'}),
 | 
				
			||||||
 | 
					                titleRepair: new T({en: 'Bike repair', nl: 'Fietsenmaker', fr: 'TODO: fr'}),
 | 
				
			||||||
 | 
					                titleShop: new T({en: 'Bike repair/shop', nl: 'Fietswinkel', fr: 'TODO: fr'}),
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                titleNamed: new T({en: 'Bike repair/shop', nl: 'Fietszaak {name}', fr: 'TODO: fr'}),
 | 
				
			||||||
 | 
					                titleRepairNamed: new T({en: 'Bike shop', nl: 'Fietsenmaker {name}', fr: 'TODO: fr'}),
 | 
				
			||||||
 | 
					                titleShopNamed: new T({en: 'Bike repair/shop', nl: 'Fietswinkel {name}', fr: 'TODO: fr'}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                retail: {
 | 
					                retail: {
 | 
				
			||||||
                    question: new T({
 | 
					                    question: new T({
 | 
				
			||||||
                        en: 'Does this shop sell bikes?',
 | 
					                        en: 'Does this shop sell bikes?',
 | 
				
			||||||
| 
						 | 
					@ -266,9 +281,9 @@ export default class Translations {
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                qName: {
 | 
					                qName: {
 | 
				
			||||||
                    question: new T({en: 'What is the name of this bicycle shop?', nl: 'Wat is de naam van deze fietswinkel?', fr: 'TODO: fr'}),
 | 
					                    question: new T({en: 'What is the name of this bicycle shop?', nl: 'Wat is de naam van deze fietszaak?', fr: 'TODO: fr'}),
 | 
				
			||||||
                    render: new T({en: 'This bicycle shop is called {name}', nl: 'Deze fietswinkel heet {name}', fr: 'TODO: fr'}),
 | 
					                    render: new T({en: 'This bicycle shop is called {name}', nl: 'Deze fietszaak heet <b>{name}</b>', fr: 'TODO: fr'}),
 | 
				
			||||||
                    template: new T({en: 'This bicycle shop is called: $$$', nl: 'Deze fietswinkel heet: $$$', fr: 'TODO: fr'})
 | 
					                    template: new T({en: 'This bicycle shop is called: $$$', nl: 'Deze fietszaak heet: <b>$$$</b>', fr: 'TODO: fr'})
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                secondHand: {
 | 
					                secondHand: {
 | 
				
			||||||
                    question: new T({en: 'Does this shop sell second-hand bikes?', nl: 'Verkoopt deze winkel tweedehands fietsen?', fr: 'TODO: fr'}),
 | 
					                    question: new T({en: 'Does this shop sell second-hand bikes?', nl: 'Verkoopt deze winkel tweedehands fietsen?', fr: 'TODO: fr'}),
 | 
				
			||||||
| 
						 | 
					@ -357,6 +372,14 @@ export default class Translations {
 | 
				
			||||||
            skip: new T({
 | 
					            skip: new T({
 | 
				
			||||||
                en: "Skip this question",
 | 
					                en: "Skip this question",
 | 
				
			||||||
                nl: "Vraag overslaan"
 | 
					                nl: "Vraag overslaan"
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            oneSkippedQuestion: new T({
 | 
				
			||||||
 | 
					                en: "One question is skipped",
 | 
				
			||||||
 | 
					                nl: "Een vraag is overgeslaan"
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            skippedQuestions: new T({
 | 
				
			||||||
 | 
					                en: "Some questions are skipped",
 | 
				
			||||||
 | 
					                nl: "Sommige vragen zijn overgeslaan"
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        }   
 | 
					        }   
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								docs/Create a theme.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								docs/Create a theme.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					# Create a theme
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A _layer_ is a set of features of a single kind, e.g. 'bookcases'.
 | 
				
			||||||
 | 
					A _layout_ is a set of layers, e.g. 'bookcases' + 'nature reserves'. They are shown together with some text on the left. They can be switched with the query parameter 'layout' in the url (thus by going to 'index.html?layout=bookcases')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want to make your own version of MapComplete, you create your own layout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Clone the repo
 | 
				
			||||||
 | 
					- Build it
 | 
				
			||||||
 | 
					- Go into 'Customazations/Layouts' and copy a file there (e.g. bookcases)
 | 
				
			||||||
 | 
					- Change the text and layer selection
 | 
				
			||||||
 | 
					- Create you layers
 | 
				
			||||||
							
								
								
									
										17
									
								
								index.ts
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								index.ts
									
										
									
									
									
								
							| 
						 | 
					@ -118,7 +118,8 @@ const secondsTillChangesAreSaved = new UIEventSource<number>(0);
 | 
				
			||||||
// This message is shown full screen on mobile devices
 | 
					// This message is shown full screen on mobile devices
 | 
				
			||||||
const fullScreenMessage = new UIEventSource<UIElement>(undefined);
 | 
					const fullScreenMessage = new UIEventSource<UIElement>(undefined);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const selectedElement = new UIEventSource<any>(undefined);
 | 
					// The latest element that was selected - used to generate the right UI at the right place
 | 
				
			||||||
 | 
					const selectedElement = new UIEventSource<{feature: any}>(undefined);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({
 | 
					const locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({
 | 
				
			||||||
| 
						 | 
					@ -166,7 +167,7 @@ const bm = new Basemap("leafletDiv", locationControl, new VariableUiElement(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ------------- Setup the layers -------------------------------
 | 
					// ------------- Setup the layers -------------------------------
 | 
				
			||||||
const addButtons: {
 | 
					const addButtons: {
 | 
				
			||||||
    name: string,
 | 
					    name: UIElement,
 | 
				
			||||||
    icon: string,
 | 
					    icon: string,
 | 
				
			||||||
    tags: Tag[],
 | 
					    tags: Tag[],
 | 
				
			||||||
    layerToAddTo: FilteredLayer
 | 
					    layerToAddTo: FilteredLayer
 | 
				
			||||||
| 
						 | 
					@ -179,9 +180,10 @@ let minZoom = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for (const layer of layoutToUse.layers) {
 | 
					for (const layer of layoutToUse.layers) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const generateInfo = (tagsES) => {
 | 
					    const generateInfo = (tagsES, feature) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return new FeatureInfoBox(
 | 
					        return new FeatureInfoBox(
 | 
				
			||||||
 | 
					            feature,
 | 
				
			||||||
            tagsES,
 | 
					            tagsES,
 | 
				
			||||||
            layer.title,
 | 
					            layer.title,
 | 
				
			||||||
            layer.elementsToShow,
 | 
					            layer.elementsToShow,
 | 
				
			||||||
| 
						 | 
					@ -195,7 +197,7 @@ for (const layer of layoutToUse.layers) {
 | 
				
			||||||
    const flayer = layer.asLayer(bm, allElements, changes, osmConnection.userDetails, selectedElement, generateInfo);
 | 
					    const flayer = layer.asLayer(bm, allElements, changes, osmConnection.userDetails, selectedElement, generateInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const addButton = {
 | 
					    const addButton = {
 | 
				
			||||||
        name: layer.name,
 | 
					        name: Translations.W(layer.name),
 | 
				
			||||||
        icon: layer.icon,
 | 
					        icon: layer.icon,
 | 
				
			||||||
        tags: layer.newElementTags,
 | 
					        tags: layer.newElementTags,
 | 
				
			||||||
        layerToAddTo: flayer
 | 
					        layerToAddTo: flayer
 | 
				
			||||||
| 
						 | 
					@ -229,7 +231,8 @@ new StrayClickHandler(bm, selectedElement, fullScreenMessage, () => {
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Show the questions and information for the selected element on the fullScreen
 | 
					 * Show the questions and information for the selected element on the fullScreen
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
selectedElement.addCallback((data) => {
 | 
					selectedElement.addCallback((feature) => {
 | 
				
			||||||
 | 
					    const data = feature.feature.properties;
 | 
				
			||||||
    // Which is the applicable set?
 | 
					    // Which is the applicable set?
 | 
				
			||||||
    for (const layer of layoutToUse.layers) {
 | 
					    for (const layer of layoutToUse.layers) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -238,6 +241,7 @@ selectedElement.addCallback((data) => {
 | 
				
			||||||
            // This layer is the layer that gives the questions
 | 
					            // This layer is the layer that gives the questions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const featureBox = new FeatureInfoBox(
 | 
					            const featureBox = new FeatureInfoBox(
 | 
				
			||||||
 | 
					                feature.feature,
 | 
				
			||||||
                allElements.getElement(data.id),
 | 
					                allElements.getElement(data.id),
 | 
				
			||||||
                layer.title,
 | 
					                layer.title,
 | 
				
			||||||
                layer.elementsToShow,
 | 
					                layer.elementsToShow,
 | 
				
			||||||
| 
						 | 
					@ -300,6 +304,3 @@ new GeoLocationHandler(bm).AttachTo("geolocate-button");
 | 
				
			||||||
// --------------- Send a ping to start various action --------
 | 
					// --------------- Send a ping to start various action --------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
locationControl.ping();
 | 
					locationControl.ping();
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
window.setTimeout(() => {Locale.language.setData("nl")}, 5000)
 | 
					 | 
				
			||||||
							
								
								
									
										23
									
								
								test.ts
									
										
									
									
									
								
							
							
						
						
									
										23
									
								
								test.ts
									
										
									
									
									
								
							| 
						 | 
					@ -2,12 +2,31 @@ import {DropDown} from "./UI/Input/DropDown";
 | 
				
			||||||
import Locale from "./UI/i18n/Locale";
 | 
					import Locale from "./UI/i18n/Locale";
 | 
				
			||||||
import Combine from "./UI/Base/Combine";
 | 
					import Combine from "./UI/Base/Combine";
 | 
				
			||||||
import Translations from "./UI/i18n/Translations";
 | 
					import Translations from "./UI/i18n/Translations";
 | 
				
			||||||
 | 
					import {TagRenderingOptions} from "./Customizations/TagRendering";
 | 
				
			||||||
 | 
					import {UIEventSource} from "./UI/UIEventSource";
 | 
				
			||||||
 | 
					import {Tag} from "./Logic/TagsFilter";
 | 
				
			||||||
 | 
					import {Changes} from "./Logic/Changes";
 | 
				
			||||||
 | 
					import {OsmConnection} from "./Logic/OsmConnection";
 | 
				
			||||||
 | 
					import Translation from "./UI/i18n/Translation";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
console.log("Hello world")
 | 
					console.log("Hello world")
 | 
				
			||||||
 | 
					Locale.language.setData("en");
 | 
				
			||||||
let languagePicker = new DropDown("", ["en", "nl"].map(lang => {
 | 
					let languagePicker = new DropDown("", ["en", "nl"].map(lang => {
 | 
				
			||||||
        return {value: lang, shown: lang}
 | 
					        return {value: lang, shown: lang}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
), Locale.language).AttachTo("maindiv");
 | 
					), Locale.language).AttachTo("maindiv");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
new Combine(["abc",Translations.t.cyclofix.title, Translations.t.cyclofix.title]).AttachTo("extradiv");
 | 
					
 | 
				
			||||||
 | 
					let tags = new UIEventSource({
 | 
				
			||||||
 | 
					    x:"y"
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					new TagRenderingOptions({
 | 
				
			||||||
 | 
					    mappings: [{k: new Tag("x","y"), txt: new Translation({en: "ENG", nl: "NED"})}]
 | 
				
			||||||
 | 
					}).construct({
 | 
				
			||||||
 | 
					    tags: tags,
 | 
				
			||||||
 | 
					    changes: new Changes(
 | 
				
			||||||
 | 
					        "cs",
 | 
				
			||||||
 | 
					        new OsmConnection(true)
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}).AttachTo("extradiv")
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue