forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			147 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import Toggle from "../Input/Toggle"
 | |
| import Svg from "../../Svg"
 | |
| import { UIEventSource } from "../../Logic/UIEventSource"
 | |
| import { SubtleButton } from "../Base/SubtleButton"
 | |
| import Combine from "../Base/Combine"
 | |
| import { Button } from "../Base/Button"
 | |
| import Translations from "../i18n/Translations"
 | |
| import SplitAction from "../../Logic/Osm/Actions/SplitAction"
 | |
| import Title from "../Base/Title"
 | |
| import BaseUIElement from "../BaseUIElement"
 | |
| import { VariableUiElement } from "../Base/VariableUIElement"
 | |
| import { LoginToggle } from "./LoginButton"
 | |
| import SvelteUIElement from "../Base/SvelteUIElement"
 | |
| import WaySplitMap from "../BigComponents/WaySplitMap.svelte"
 | |
| import { Feature, Point } from "geojson"
 | |
| import { WayId } from "../../Models/OsmFeature"
 | |
| import { OsmConnection } from "../../Logic/Osm/OsmConnection"
 | |
| import { Changes } from "../../Logic/Osm/Changes"
 | |
| import { IndexedFeatureSource } from "../../Logic/FeatureSource/FeatureSource"
 | |
| import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
 | |
| import OsmObjectDownloader from "../../Logic/Osm/OsmObjectDownloader"
 | |
| 
 | |
| export default class SplitRoadWizard extends Combine {
 | |
|     public dialogIsOpened: UIEventSource<boolean>
 | |
| 
 | |
|     /**
 | |
|      * A UI Element used for splitting roads
 | |
|      *
 | |
|      * @param id: The id of the road to remove
 | |
|      * @param state: the state of the application
 | |
|      */
 | |
|     constructor(
 | |
|         id: WayId,
 | |
|         state: {
 | |
|             layout?: LayoutConfig
 | |
|             osmConnection?: OsmConnection
 | |
|             osmObjectDownloader?: OsmObjectDownloader
 | |
|             changes?: Changes
 | |
|             indexedFeatures?: IndexedFeatureSource
 | |
|             selectedElement?: UIEventSource<Feature>
 | |
|         }
 | |
|     ) {
 | |
|         const t = Translations.t.split
 | |
| 
 | |
|         // Contains the points on the road that are selected to split on - contains geojson points with extra properties such as 'location' with the distance along the linestring
 | |
|         const splitPoints = new UIEventSource<Feature<Point>[]>([])
 | |
| 
 | |
|         const hasBeenSplit = new UIEventSource(false)
 | |
| 
 | |
|         // Toggle variable between show split button and map
 | |
|         const splitClicked = new UIEventSource<boolean>(false)
 | |
| 
 | |
|         const leafletMap = new UIEventSource<BaseUIElement>(undefined)
 | |
| 
 | |
|         function initMap() {
 | |
|             ;(async function (
 | |
|                 id: WayId,
 | |
|                 splitPoints: UIEventSource<Feature[]>
 | |
|             ): Promise<BaseUIElement> {
 | |
|                 return new SvelteUIElement(WaySplitMap, {
 | |
|                     osmWay: await state.osmObjectDownloader.DownloadObjectAsync(id),
 | |
|                     splitPoints,
 | |
|                 })
 | |
|             })(id, splitPoints).then((mapComponent) =>
 | |
|                 leafletMap.setData(mapComponent.SetClass("w-full h-80"))
 | |
|             )
 | |
|         }
 | |
| 
 | |
|         // 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
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         const splitToggle = new LoginToggle(splitButton, t.loginToSplit.Clone(), state)
 | |
| 
 | |
|         // 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) => <[number, number]>(<Point>ff.geometry).coordinates),
 | |
|                 {
 | |
|                     theme: state?.layout?.id,
 | |
|                 },
 | |
|                 5
 | |
|             )
 | |
|             await state.changes?.applyAction(splitAction)
 | |
|             // We throw away the old map and splitpoints, and create a new map from scratch
 | |
|             splitPoints.setData([])
 | |
| 
 | |
|             // Close the popup. The contributor has to select a segment again to make sure they continue editing the correct segment; see #1219
 | |
|             state.selectedElement?.setData(undefined)
 | |
|         })
 | |
| 
 | |
|         saveButton.SetClass("btn btn-primary mr-3")
 | |
|         const disabledSaveButton = new Button(t.split.Clone(), 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),
 | |
|         ])
 | |
|         splitClicked.addCallback((view) => {
 | |
|             if (view) {
 | |
|                 initMap()
 | |
|             }
 | |
|         })
 | |
|         this.dialogIsOpened = splitClicked
 | |
|         const self = this
 | |
|         splitButton.onClick(() => {
 | |
|             splitClicked.setData(true)
 | |
|             self.ScrollIntoView()
 | |
|         })
 | |
|     }
 | |
| }
 |