forked from MapComplete/MapComplete
		
	
							parent
							
								
									c8971a1cbe
								
							
						
					
					
						commit
						8f51dd8d64
					
				
					 4 changed files with 123 additions and 70 deletions
				
			
		| 
						 | 
					@ -16,6 +16,7 @@ export default class SplitAction extends OsmChangeAction {
 | 
				
			||||||
    private readonly _splitPointsCoordinates: [number, number][] // lon, lat
 | 
					    private readonly _splitPointsCoordinates: [number, number][] // lon, lat
 | 
				
			||||||
    private _meta: { theme: string; changeType: "split" }
 | 
					    private _meta: { theme: string; changeType: "split" }
 | 
				
			||||||
    private _toleranceInMeters: number
 | 
					    private _toleranceInMeters: number
 | 
				
			||||||
 | 
					    private _withNewCoordinates: (coordinates: [number, number][]) => void
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Create a changedescription for splitting a point.
 | 
					     * Create a changedescription for splitting a point.
 | 
				
			||||||
| 
						 | 
					@ -24,17 +25,20 @@ export default class SplitAction extends OsmChangeAction {
 | 
				
			||||||
     * @param splitPointCoordinates: lon, lat
 | 
					     * @param splitPointCoordinates: lon, lat
 | 
				
			||||||
     * @param meta
 | 
					     * @param meta
 | 
				
			||||||
     * @param toleranceInMeters: if a splitpoint closer then this amount of meters to an existing point, the existing point will be used to split the line instead of a new point
 | 
					     * @param toleranceInMeters: if a splitpoint closer then this amount of meters to an existing point, the existing point will be used to split the line instead of a new point
 | 
				
			||||||
 | 
					     * @param withNewCoordinates: an optional callback which will leak the new coordinates of the original way
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    constructor(
 | 
					    constructor(
 | 
				
			||||||
        wayId: string,
 | 
					        wayId: string,
 | 
				
			||||||
        splitPointCoordinates: [number, number][],
 | 
					        splitPointCoordinates: [number, number][],
 | 
				
			||||||
        meta: { theme: string },
 | 
					        meta: { theme: string },
 | 
				
			||||||
        toleranceInMeters = 5
 | 
					        toleranceInMeters = 5,
 | 
				
			||||||
 | 
					        withNewCoordinates?: (coordinates: [number, number][]) => void
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        super(wayId, true)
 | 
					        super(wayId, true)
 | 
				
			||||||
        this.wayId = wayId
 | 
					        this.wayId = wayId
 | 
				
			||||||
        this._splitPointsCoordinates = splitPointCoordinates
 | 
					        this._splitPointsCoordinates = splitPointCoordinates
 | 
				
			||||||
        this._toleranceInMeters = toleranceInMeters
 | 
					        this._toleranceInMeters = toleranceInMeters
 | 
				
			||||||
 | 
					        this._withNewCoordinates = withNewCoordinates
 | 
				
			||||||
        this._meta = { ...meta, changeType: "split" }
 | 
					        this._meta = { ...meta, changeType: "split" }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,7 +63,7 @@ export default class SplitAction extends OsmChangeAction {
 | 
				
			||||||
        const originalElement = <OsmWay>await OsmObject.DownloadObjectAsync(this.wayId)
 | 
					        const originalElement = <OsmWay>await OsmObject.DownloadObjectAsync(this.wayId)
 | 
				
			||||||
        const originalNodes = originalElement.nodes
 | 
					        const originalNodes = originalElement.nodes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // First, calculate splitpoints and remove points close to one another
 | 
					        // First, calculate the splitpoints and remove points close to one another
 | 
				
			||||||
        const splitInfo = this.CalculateSplitCoordinates(originalElement, this._toleranceInMeters)
 | 
					        const splitInfo = this.CalculateSplitCoordinates(originalElement, this._toleranceInMeters)
 | 
				
			||||||
        // Now we have a list with e.g.
 | 
					        // Now we have a list with e.g.
 | 
				
			||||||
        // [ { originalIndex: 0}, {originalIndex: 1, doSplit: true}, {originalIndex: 2}, {originalIndex: undefined, doSplit: true}, {originalIndex: 3}]
 | 
					        // [ { originalIndex: 0}, {originalIndex: 1, doSplit: true}, {originalIndex: 2}, {originalIndex: undefined, doSplit: true}, {originalIndex: 3}]
 | 
				
			||||||
| 
						 | 
					@ -90,7 +94,7 @@ export default class SplitAction extends OsmChangeAction {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const changeDescription: ChangeDescription[] = []
 | 
					        const changeDescription: ChangeDescription[] = []
 | 
				
			||||||
        // Let's create the new points as needed
 | 
					        // Let's create the new nodes as needed
 | 
				
			||||||
        for (const element of splitInfo) {
 | 
					        for (const element of splitInfo) {
 | 
				
			||||||
            if (element.originalIndex >= 0) {
 | 
					            if (element.originalIndex >= 0) {
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
| 
						 | 
					@ -114,17 +118,21 @@ export default class SplitAction extends OsmChangeAction {
 | 
				
			||||||
        for (const wayPart of wayParts) {
 | 
					        for (const wayPart of wayParts) {
 | 
				
			||||||
            let isOriginal = wayPart === longest
 | 
					            let isOriginal = wayPart === longest
 | 
				
			||||||
            if (isOriginal) {
 | 
					            if (isOriginal) {
 | 
				
			||||||
                // We change the actual element!
 | 
					                // We change the existing way
 | 
				
			||||||
                const nodeIds = wayPart.map((p) => p.originalIndex)
 | 
					                const nodeIds = wayPart.map((p) => p.originalIndex)
 | 
				
			||||||
 | 
					                const newCoordinates = wayPart.map((p) => p.lngLat)
 | 
				
			||||||
                changeDescription.push({
 | 
					                changeDescription.push({
 | 
				
			||||||
                    type: "way",
 | 
					                    type: "way",
 | 
				
			||||||
                    id: originalElement.id,
 | 
					                    id: originalElement.id,
 | 
				
			||||||
                    changes: {
 | 
					                    changes: {
 | 
				
			||||||
                        coordinates: wayPart.map((p) => p.lngLat),
 | 
					                        coordinates: newCoordinates,
 | 
				
			||||||
                        nodes: nodeIds,
 | 
					                        nodes: nodeIds,
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    meta: this._meta,
 | 
					                    meta: this._meta,
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
 | 
					                if (this._withNewCoordinates) {
 | 
				
			||||||
 | 
					                    this._withNewCoordinates(newCoordinates)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                allWayIdsInOrder.push(originalElement.id)
 | 
					                allWayIdsInOrder.push(originalElement.id)
 | 
				
			||||||
                allWaysNodesInOrder.push(nodeIds)
 | 
					                allWaysNodesInOrder.push(nodeIds)
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
| 
						 | 
					@ -141,6 +149,10 @@ export default class SplitAction extends OsmChangeAction {
 | 
				
			||||||
                    kv.push({ k: k, v: originalElement.tags[k] })
 | 
					                    kv.push({ k: k, v: originalElement.tags[k] })
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                const nodeIds = wayPart.map((p) => p.originalIndex)
 | 
					                const nodeIds = wayPart.map((p) => p.originalIndex)
 | 
				
			||||||
 | 
					                if (nodeIds.length <= 1) {
 | 
				
			||||||
 | 
					                    console.error("Got a segment with only one node - skipping")
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                changeDescription.push({
 | 
					                changeDescription.push({
 | 
				
			||||||
                    type: "way",
 | 
					                    type: "way",
 | 
				
			||||||
                    id: id,
 | 
					                    id: id,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,8 +22,10 @@ import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
 | 
				
			||||||
import { ElementStorage } from "../../Logic/ElementStorage"
 | 
					import { ElementStorage } from "../../Logic/ElementStorage"
 | 
				
			||||||
import BaseLayer from "../../Models/BaseLayer"
 | 
					import BaseLayer from "../../Models/BaseLayer"
 | 
				
			||||||
import FilteredLayer from "../../Models/FilteredLayer"
 | 
					import FilteredLayer from "../../Models/FilteredLayer"
 | 
				
			||||||
 | 
					import BaseUIElement from "../BaseUIElement"
 | 
				
			||||||
 | 
					import { VariableUiElement } from "../Base/VariableUIElement"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class SplitRoadWizard extends Toggle {
 | 
					export default class SplitRoadWizard extends Combine {
 | 
				
			||||||
    // @ts-ignore
 | 
					    // @ts-ignore
 | 
				
			||||||
    private static splitLayerStyling = new LayerConfig(
 | 
					    private static splitLayerStyling = new LayerConfig(
 | 
				
			||||||
        split_point,
 | 
					        split_point,
 | 
				
			||||||
| 
						 | 
					@ -63,6 +65,106 @@ export default class SplitRoadWizard extends Toggle {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Toggle variable between show split button and map
 | 
					        // Toggle variable between show split button and map
 | 
				
			||||||
        const splitClicked = new UIEventSource<boolean>(false)
 | 
					        const splitClicked = new UIEventSource<boolean>(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const leafletMap = new UIEventSource<BaseUIElement>(
 | 
				
			||||||
 | 
					            SplitRoadWizard.setupMapComponent(id, splitPoints, state)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Toggle between splitmap
 | 
				
			||||||
 | 
					        const splitButton = new SubtleButton(
 | 
				
			||||||
 | 
					            Svg.scissors_ui().SetStyle("height: 1.5rem; width: auto"),
 | 
				
			||||||
 | 
					            new Toggle(
 | 
				
			||||||
 | 
					                t.splitAgain.Clone().SetClass("text-lg font-bold"),
 | 
				
			||||||
 | 
					                t.inviteToSplit.Clone().SetClass("text-lg font-bold"),
 | 
				
			||||||
 | 
					                hasBeenSplit
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        splitButton.onClick(() => {
 | 
				
			||||||
 | 
					            splitClicked.setData(true)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Only show the splitButton if logged in, else show login prompt
 | 
				
			||||||
 | 
					        const loginBtn = t.loginToSplit
 | 
				
			||||||
 | 
					            .Clone()
 | 
				
			||||||
 | 
					            .onClick(() => state.osmConnection.AttemptLogin())
 | 
				
			||||||
 | 
					            .SetClass("login-button-friendly")
 | 
				
			||||||
 | 
					        const splitToggle = new Toggle(splitButton, loginBtn, state.osmConnection.isLoggedIn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Save button
 | 
				
			||||||
 | 
					        const saveButton = new Button(t.split.Clone(), async () => {
 | 
				
			||||||
 | 
					            hasBeenSplit.setData(true)
 | 
				
			||||||
 | 
					            splitClicked.setData(false)
 | 
				
			||||||
 | 
					            const splitAction = new SplitAction(
 | 
				
			||||||
 | 
					                id,
 | 
				
			||||||
 | 
					                splitPoints.data.map((ff) => ff.feature.geometry.coordinates),
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    theme: state?.layoutToUse?.id,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                5,
 | 
				
			||||||
 | 
					                (coordinates) => {
 | 
				
			||||||
 | 
					                    state.allElements.ContainingFeatures.get(id).geometry["coordinates"] =
 | 
				
			||||||
 | 
					                        coordinates
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            await state.changes.applyAction(splitAction)
 | 
				
			||||||
 | 
					            // We throw away the old map and splitpoints, and create a new map from scratch
 | 
				
			||||||
 | 
					            splitPoints.setData([])
 | 
				
			||||||
 | 
					            leafletMap.setData(SplitRoadWizard.setupMapComponent(id, splitPoints, state))
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        saveButton.SetClass("btn btn-primary mr-3")
 | 
				
			||||||
 | 
					        const disabledSaveButton = new Button("Split", undefined)
 | 
				
			||||||
 | 
					        disabledSaveButton.SetClass("btn btn-disabled mr-3")
 | 
				
			||||||
 | 
					        // Only show the save button if there are split points defined
 | 
				
			||||||
 | 
					        const saveToggle = new Toggle(
 | 
				
			||||||
 | 
					            disabledSaveButton,
 | 
				
			||||||
 | 
					            saveButton,
 | 
				
			||||||
 | 
					            splitPoints.map((data) => data.length === 0)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const cancelButton = Translations.t.general.cancel
 | 
				
			||||||
 | 
					            .Clone() // Not using Button() element to prevent full width button
 | 
				
			||||||
 | 
					            .SetClass("btn btn-secondary mr-3")
 | 
				
			||||||
 | 
					            .onClick(() => {
 | 
				
			||||||
 | 
					                splitPoints.setData([])
 | 
				
			||||||
 | 
					                splitClicked.setData(false)
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cancelButton.SetClass("btn btn-secondary block")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const splitTitle = new Title(t.splitTitle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const mapView = new Combine([
 | 
				
			||||||
 | 
					            splitTitle,
 | 
				
			||||||
 | 
					            new VariableUiElement(leafletMap),
 | 
				
			||||||
 | 
					            new Combine([cancelButton, saveToggle]).SetClass("flex flex-row"),
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					        mapView.SetClass("question")
 | 
				
			||||||
 | 
					        super([
 | 
				
			||||||
 | 
					            Toggle.If(hasBeenSplit, () =>
 | 
				
			||||||
 | 
					                t.hasBeenSplit.Clone().SetClass("font-bold thanks block w-full")
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            new Toggle(mapView, splitToggle, splitClicked),
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					        this.dialogIsOpened = splitClicked
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static setupMapComponent(
 | 
				
			||||||
 | 
					        id: string,
 | 
				
			||||||
 | 
					        splitPoints: UIEventSource<{ feature: any; freshness: Date }[]>,
 | 
				
			||||||
 | 
					        state: {
 | 
				
			||||||
 | 
					            filteredLayers: UIEventSource<FilteredLayer[]>
 | 
				
			||||||
 | 
					            backgroundLayer: UIEventSource<BaseLayer>
 | 
				
			||||||
 | 
					            featureSwitchIsTesting: UIEventSource<boolean>
 | 
				
			||||||
 | 
					            featureSwitchIsDebugging: UIEventSource<boolean>
 | 
				
			||||||
 | 
					            featureSwitchShowAllQuestions: UIEventSource<boolean>
 | 
				
			||||||
 | 
					            osmConnection: OsmConnection
 | 
				
			||||||
 | 
					            featureSwitchUserbadge: UIEventSource<boolean>
 | 
				
			||||||
 | 
					            changes: Changes
 | 
				
			||||||
 | 
					            layoutToUse: LayoutConfig
 | 
				
			||||||
 | 
					            allElements: ElementStorage
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ): BaseUIElement {
 | 
				
			||||||
        // Load the road with given id on the minimap
 | 
					        // Load the road with given id on the minimap
 | 
				
			||||||
        const roadElement = state.allElements.ContainingFeatures.get(id)
 | 
					        const roadElement = state.allElements.ContainingFeatures.get(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,7 +198,6 @@ export default class SplitRoadWizard extends Toggle {
 | 
				
			||||||
            layerToShow: SplitRoadWizard.splitLayerStyling,
 | 
					            layerToShow: SplitRoadWizard.splitLayerStyling,
 | 
				
			||||||
            state,
 | 
					            state,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * Handles a click on the overleaf map.
 | 
					         * Handles a click on the overleaf map.
 | 
				
			||||||
         * Finds the closest intersection with the road and adds a point there, ready to confirm the cut.
 | 
					         * Finds the closest intersection with the road and adds a point there, ready to confirm the cut.
 | 
				
			||||||
| 
						 | 
					@ -137,67 +238,6 @@ export default class SplitRoadWizard extends Toggle {
 | 
				
			||||||
                onMapClick([mouseEvent.latlng.lng, mouseEvent.latlng.lat])
 | 
					                onMapClick([mouseEvent.latlng.lng, mouseEvent.latlng.lat])
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        return miniMap
 | 
				
			||||||
        // Toggle between splitmap
 | 
					 | 
				
			||||||
        const splitButton = new SubtleButton(
 | 
					 | 
				
			||||||
            Svg.scissors_ui().SetStyle("height: 1.5rem; width: auto"),
 | 
					 | 
				
			||||||
            t.inviteToSplit.Clone().SetClass("text-lg font-bold")
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        splitButton.onClick(() => {
 | 
					 | 
				
			||||||
            splitClicked.setData(true)
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Only show the splitButton if logged in, else show login prompt
 | 
					 | 
				
			||||||
        const loginBtn = t.loginToSplit
 | 
					 | 
				
			||||||
            .Clone()
 | 
					 | 
				
			||||||
            .onClick(() => state.osmConnection.AttemptLogin())
 | 
					 | 
				
			||||||
            .SetClass("login-button-friendly")
 | 
					 | 
				
			||||||
        const splitToggle = new Toggle(splitButton, loginBtn, state.osmConnection.isLoggedIn)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Save button
 | 
					 | 
				
			||||||
        const saveButton = new Button(t.split.Clone(), () => {
 | 
					 | 
				
			||||||
            hasBeenSplit.setData(true)
 | 
					 | 
				
			||||||
            state.changes.applyAction(
 | 
					 | 
				
			||||||
                new SplitAction(
 | 
					 | 
				
			||||||
                    id,
 | 
					 | 
				
			||||||
                    splitPoints.data.map((ff) => ff.feature.geometry.coordinates),
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        theme: state?.layoutToUse?.id,
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        saveButton.SetClass("btn btn-primary mr-3")
 | 
					 | 
				
			||||||
        const disabledSaveButton = new Button("Split", undefined)
 | 
					 | 
				
			||||||
        disabledSaveButton.SetClass("btn btn-disabled mr-3")
 | 
					 | 
				
			||||||
        // Only show the save button if there are split points defined
 | 
					 | 
				
			||||||
        const saveToggle = new Toggle(
 | 
					 | 
				
			||||||
            disabledSaveButton,
 | 
					 | 
				
			||||||
            saveButton,
 | 
					 | 
				
			||||||
            splitPoints.map((data) => data.length === 0)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const cancelButton = Translations.t.general.cancel
 | 
					 | 
				
			||||||
            .Clone() // Not using Button() element to prevent full width button
 | 
					 | 
				
			||||||
            .SetClass("btn btn-secondary mr-3")
 | 
					 | 
				
			||||||
            .onClick(() => {
 | 
					 | 
				
			||||||
                splitPoints.setData([])
 | 
					 | 
				
			||||||
                splitClicked.setData(false)
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cancelButton.SetClass("btn btn-secondary block")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const splitTitle = new Title(t.splitTitle)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const mapView = new Combine([
 | 
					 | 
				
			||||||
            splitTitle,
 | 
					 | 
				
			||||||
            miniMap,
 | 
					 | 
				
			||||||
            new Combine([cancelButton, saveToggle]).SetClass("flex flex-row"),
 | 
					 | 
				
			||||||
        ])
 | 
					 | 
				
			||||||
        mapView.SetClass("question")
 | 
					 | 
				
			||||||
        const confirm = new Toggle(mapView, splitToggle, splitClicked)
 | 
					 | 
				
			||||||
        super(t.hasBeenSplit.Clone(), confirm, hasBeenSplit)
 | 
					 | 
				
			||||||
        this.dialogIsOpened = splitClicked
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -913,6 +913,7 @@
 | 
				
			||||||
        "inviteToSplit": "Split this road in smaller segments. This allows to give different properties to parts of the road.",
 | 
					        "inviteToSplit": "Split this road in smaller segments. This allows to give different properties to parts of the road.",
 | 
				
			||||||
        "loginToSplit": "You must be logged in to split a road",
 | 
					        "loginToSplit": "You must be logged in to split a road",
 | 
				
			||||||
        "split": "Split",
 | 
					        "split": "Split",
 | 
				
			||||||
 | 
					        "splitAgain": "Split this road again",
 | 
				
			||||||
        "splitTitle": "Choose on the map where the properties of this road change"
 | 
					        "splitTitle": "Choose on the map where the properties of this road change"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "translations": {
 | 
					    "translations": {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7594,7 +7594,7 @@ describe("GenerateCache", () => {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        mkdirSync(dir + "np-cache")
 | 
					        mkdirSync(dir + "np-cache")
 | 
				
			||||||
        initDownloads(
 | 
					        initDownloads(
 | 
				
			||||||
            "(nwr%5B%22amenity%22%3D%22toilets%22%5D%3Bnwr%5B%22amenity%22%3D%22parking%22%5D%3Bnwr%5B%22amenity%22%3D%22bench%22%5D%3Bnwr%5B%22id%22%3D%22location_track%22%5D%3Bnwr%5B%22id%22%3D%22gps%22%5D%3Bnwr%5B%22information%22%3D%22board%22%5D%3Bnwr%5B%22leisure%22%3D%22picnic_table%22%5D%3Bnwr%5B%22man_made%22%3D%22watermill%22%5D%3Bnwr%5B%22selected%22%3D%22yes%22%5D%3Bnwr%5B%22user%3Ahome%22%3D%22yes%22%5D%3Bnwr%5B%22user%3Alocation%22%3D%22yes%22%5D%3Bnwr%5B%22leisure%22%3D%22nature_reserve%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22boundary%22%3D%22protected_area%22%5D%5B%22protect_class%22!%3D%2298%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22information%22%3D%22visitor_centre%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22information%22%3D%22office%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*foot.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*hiking.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*bycicle.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*horse.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22leisure%22%3D%22bird_hide%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22amenity%22%3D%22drinking_water%22%5D%5B%22man_made%22!%3D%22reservoir_covered%22%5D%5B%22access%22!%3D%22permissive%22%5D%5B%22access%22!%3D%22private%22%5D%3Bnwr%5B%22drinking_water%22%3D%22yes%22%5D%5B%22man_made%22!%3D%22reservoir_covered%22%5D%5B%22access%22!%3D%22permissive%22%5D%5B%22access%22!%3D%22private%22%5D%3B)%3Bout%20body%3Bout%20meta%3B%3E%3Bout%20skel%20qt%3B"
 | 
					            "(nwr%5B%22amenity%22%3D%22toilets%22%5D%3Bnwr%5B%22amenity%22%3D%22parking%22%5D%3Bnwr%5B%22amenity%22%3D%22bench%22%5D%3Bnwr%5B%22id%22%3D%22location_track%22%5D%3Bnwr%5B%22id%22%3D%22gps%22%5D%3Bnwr%5B%22information%22%3D%22board%22%5D%3Bnwr%5B%22leisure%22%3D%22picnic_table%22%5D%3Bnwr%5B%22selected%22%3D%22yes%22%5D%3Bnwr%5B%22user%3Ahome%22%3D%22yes%22%5D%3Bnwr%5B%22user%3Alocation%22%3D%22yes%22%5D%3Bnwr%5B%22leisure%22%3D%22nature_reserve%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22boundary%22%3D%22protected_area%22%5D%5B%22protect_class%22!%3D%2298%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22information%22%3D%22visitor_centre%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22information%22%3D%22office%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*foot.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*hiking.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*bycicle.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*horse.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22leisure%22%3D%22bird_hide%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22amenity%22%3D%22drinking_water%22%5D%5B%22man_made%22!%3D%22reservoir_covered%22%5D%5B%22access%22!%3D%22permissive%22%5D%5B%22access%22!%3D%22private%22%5D%3Bnwr%5B%22drinking_water%22%3D%22yes%22%5D%5B%22man_made%22!%3D%22reservoir_covered%22%5D%5B%22access%22!%3D%22permissive%22%5D%5B%22access%22!%3D%22private%22%5D%3B)%3Bout%20body%3Bout%20meta%3B%3E%3Bout%20skel%20qt%3B"
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        await main([
 | 
					        await main([
 | 
				
			||||||
            "natuurpunt",
 | 
					            "natuurpunt",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue