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()
|
|
})
|
|
}
|
|
}
|