forked from MapComplete/MapComplete
		
	
		
			
	
	
		
			184 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			184 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | import {UIEventSource} from "../../Logic/UIEventSource"; | ||
|  | import {OsmConnection} from "../../Logic/Osm/OsmConnection"; | ||
|  | import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline"; | ||
|  | import BaseUIElement from "../BaseUIElement"; | ||
|  | import LocationInput from "../Input/LocationInput"; | ||
|  | import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"; | ||
|  | import {BBox} from "../../Logic/BBox"; | ||
|  | import {TagUtils} from "../../Logic/Tags/TagUtils"; | ||
|  | import {SubtleButton} from "../Base/SubtleButton"; | ||
|  | import Combine from "../Base/Combine"; | ||
|  | import Translations from "../i18n/Translations"; | ||
|  | import Svg from "../../Svg"; | ||
|  | import Toggle from "../Input/Toggle"; | ||
|  | import SimpleAddUI, {PresetInfo} from "../BigComponents/SimpleAddUI"; | ||
|  | 
 | ||
|  | export default class ConfirmLocationOfPoint extends Combine { | ||
|  | 
 | ||
|  | 
 | ||
|  |     constructor( | ||
|  |         state: { | ||
|  |             osmConnection: OsmConnection, | ||
|  |             featurePipeline: FeaturePipeline | ||
|  |         }, | ||
|  |         filterViewIsOpened: UIEventSource<boolean>, | ||
|  |         preset: PresetInfo, | ||
|  |         confirmText: BaseUIElement, | ||
|  |         loc: { lon: number, lat: number }, | ||
|  |         confirm: (tags: any[], location: { lat: number, lon: number }, snapOntoWayId: string) => void, | ||
|  |         cancel: () => void, | ||
|  |     ) { | ||
|  | 
 | ||
|  |         let preciseInput: LocationInput = undefined | ||
|  |         if (preset.preciseInput !== undefined) { | ||
|  |             // We uncouple the event source
 | ||
|  |             const zloc = {...loc, zoom: 19} | ||
|  |             const locationSrc = new UIEventSource(zloc); | ||
|  | 
 | ||
|  |             let backgroundLayer = undefined; | ||
|  |             if (preset.preciseInput.preferredBackground) { | ||
|  |                 backgroundLayer = AvailableBaseLayers.SelectBestLayerAccordingTo(locationSrc, new UIEventSource<string | string[]>(preset.preciseInput.preferredBackground)) | ||
|  |             } | ||
|  | 
 | ||
|  |             let snapToFeatures: UIEventSource<{ feature: any }[]> = undefined | ||
|  |             let mapBounds: UIEventSource<BBox> = undefined | ||
|  |             if (preset.preciseInput.snapToLayers && preset.preciseInput.snapToLayers.length > 0) { | ||
|  |                 snapToFeatures = new UIEventSource<{ feature: any }[]>([]) | ||
|  |                 mapBounds = new UIEventSource<BBox>(undefined) | ||
|  |             } | ||
|  | 
 | ||
|  | 
 | ||
|  |             const tags = TagUtils.KVtoProperties(preset.tags ?? []); | ||
|  |             preciseInput = new LocationInput({ | ||
|  |                 mapBackground: backgroundLayer, | ||
|  |                 centerLocation: locationSrc, | ||
|  |                 snapTo: snapToFeatures, | ||
|  |                 snappedPointTags: tags, | ||
|  |                 maxSnapDistance: preset.preciseInput.maxSnapDistance, | ||
|  |                 bounds: mapBounds | ||
|  |             }) | ||
|  |             preciseInput.installBounds(0.15, true) | ||
|  |             preciseInput.SetClass("h-32 rounded-xl overflow-hidden border border-gray").SetStyle("height: 12rem;") | ||
|  | 
 | ||
|  | 
 | ||
|  |             if (preset.preciseInput.snapToLayers && preset.preciseInput.snapToLayers.length > 0) { | ||
|  |                 // We have to snap to certain layers.
 | ||
|  |                 // Lets fetch them
 | ||
|  | 
 | ||
|  |                 let loadedBbox: BBox = undefined | ||
|  |                 mapBounds?.addCallbackAndRunD(bbox => { | ||
|  |                     if (loadedBbox !== undefined && bbox.isContainedIn(loadedBbox)) { | ||
|  |                         // All is already there
 | ||
|  |                         // return;
 | ||
|  |                     } | ||
|  | 
 | ||
|  |                     bbox = bbox.pad(2); | ||
|  |                     loadedBbox = bbox; | ||
|  |                     const allFeatures: { feature: any }[] = [] | ||
|  |                     preset.preciseInput.snapToLayers.forEach(layerId => { | ||
|  |                         console.log("Snapping to", layerId) | ||
|  |                         state.featurePipeline.GetFeaturesWithin(layerId, bbox)?.forEach(feats => allFeatures.push(...feats.map(f => ({feature: f})))) | ||
|  |                     }) | ||
|  |                     console.log("Snapping to", allFeatures) | ||
|  |                     snapToFeatures.setData(allFeatures) | ||
|  |                 }) | ||
|  |             } | ||
|  | 
 | ||
|  |         } | ||
|  | 
 | ||
|  | 
 | ||
|  |         let confirmButton: BaseUIElement = new SubtleButton(preset.icon(), | ||
|  |             new Combine([ | ||
|  |                 confirmText, | ||
|  |                 Translations.t.general.add.warnVisibleForEveryone.Clone().SetClass("alert") | ||
|  |             ]).SetClass("flex flex-col") | ||
|  |         ).SetClass("font-bold break-words") | ||
|  |             .onClick(() => { | ||
|  |                 confirm(preset.tags, (preciseInput?.GetValue()?.data ?? loc), preciseInput?.snappedOnto?.data?.properties?.id); | ||
|  |             }); | ||
|  | 
 | ||
|  |         if (preciseInput !== undefined) { | ||
|  |             confirmButton = new Combine([preciseInput, confirmButton]) | ||
|  |         } | ||
|  | 
 | ||
|  |         const openLayerControl = | ||
|  |             new SubtleButton( | ||
|  |                 Svg.layers_ui(), | ||
|  |                 new Combine([ | ||
|  |                     Translations.t.general.add.layerNotEnabled | ||
|  |                         .Subs({layer: preset.layerToAddTo.layerDef.name}) | ||
|  |                         .SetClass("alert"), | ||
|  |                     Translations.t.general.add.openLayerControl | ||
|  |                 ]) | ||
|  |             ) | ||
|  |                 .onClick(() => filterViewIsOpened.setData(true)) | ||
|  | 
 | ||
|  | 
 | ||
|  |         const openLayerOrConfirm = new Toggle( | ||
|  |             confirmButton, | ||
|  |             openLayerControl, | ||
|  |             preset.layerToAddTo.isDisplayed | ||
|  |         ) | ||
|  | 
 | ||
|  |         const disableFilter = new SubtleButton( | ||
|  |             new Combine([ | ||
|  |                 Svg.filter_ui().SetClass("absolute w-full"), | ||
|  |                 Svg.cross_bottom_right_svg().SetClass("absolute red-svg") | ||
|  |             ]).SetClass("relative"), | ||
|  |             new Combine( | ||
|  |                 [ | ||
|  |                     Translations.t.general.add.disableFiltersExplanation.Clone(), | ||
|  |                     Translations.t.general.add.disableFilters.Clone().SetClass("text-xl") | ||
|  |                 ] | ||
|  |             ).SetClass("flex flex-col") | ||
|  |         ).onClick(() => { | ||
|  |             preset.layerToAddTo.appliedFilters.setData([]) | ||
|  |             cancel() | ||
|  |         }) | ||
|  | 
 | ||
|  |         const disableFiltersOrConfirm = new Toggle( | ||
|  |             openLayerOrConfirm, | ||
|  |             disableFilter, | ||
|  |             preset.layerToAddTo.appliedFilters.map(filters => { | ||
|  |                 if (filters === undefined || filters.length === 0) { | ||
|  |                     return true; | ||
|  |                 } | ||
|  |                 for (const filter of filters) { | ||
|  |                     if (filter.selected === 0 && filter.filter.options.length === 1) { | ||
|  |                         return false; | ||
|  |                     } | ||
|  |                     if (filter.selected !== undefined) { | ||
|  |                         const tags = filter.filter.options[filter.selected].osmTags | ||
|  |                         if (tags !== undefined && tags["and"]?.length !== 0) { | ||
|  |                             // This actually doesn't filter anything at all
 | ||
|  |                             return false; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |                 return true | ||
|  | 
 | ||
|  |             }) | ||
|  |         ) | ||
|  | 
 | ||
|  | 
 | ||
|  |         const tagInfo = SimpleAddUI.CreateTagInfoFor(preset, state.osmConnection); | ||
|  | 
 | ||
|  |         const cancelButton = new SubtleButton(Svg.close_ui(), | ||
|  |             Translations.t.general.cancel | ||
|  |         ).onClick(cancel) | ||
|  | 
 | ||
|  |         super([ | ||
|  |             state.osmConnection.userDetails.data.dryRun ? | ||
|  |                 Translations.t.general.testing.Clone().SetClass("alert") : undefined, | ||
|  |             disableFiltersOrConfirm, | ||
|  |             cancelButton, | ||
|  |             preset.description, | ||
|  |             tagInfo | ||
|  | 
 | ||
|  |         ]) | ||
|  | 
 | ||
|  |         this.SetClass("flex flex-col") | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  | } |