forked from MapComplete/MapComplete
		
	Add precise input method, enabled for public bookcases
This commit is contained in:
		
							parent
							
								
									42d0071b26
								
							
						
					
					
						commit
						315e2f7fd1
					
				
					 10 changed files with 318 additions and 64 deletions
				
			
		|  | @ -54,6 +54,7 @@ export default class LayerConfig { | ||||||
|         title: Translation, |         title: Translation, | ||||||
|         tags: Tag[], |         tags: Tag[], | ||||||
|         description?: Translation, |         description?: Translation, | ||||||
|  |         preciseInput?: {preferredBackground?: string} | ||||||
|     }[]; |     }[]; | ||||||
| 
 | 
 | ||||||
|     tagRenderings: TagRenderingConfig []; |     tagRenderings: TagRenderingConfig []; | ||||||
|  | @ -130,12 +131,19 @@ export default class LayerConfig { | ||||||
|         this.minzoom = json.minzoom ?? 0; |         this.minzoom = json.minzoom ?? 0; | ||||||
|         this.maxzoom = json.maxzoom ?? 1000; |         this.maxzoom = json.maxzoom ?? 1000; | ||||||
|         this.wayHandling = json.wayHandling ?? 0; |         this.wayHandling = json.wayHandling ?? 0; | ||||||
|         this.presets = (json.presets ?? []).map((pr, i) => |         this.presets = (json.presets ?? []).map((pr, i) => { | ||||||
|             ({ |             if(pr.preciseInput === true){ | ||||||
|  |                 pr.preciseInput = { | ||||||
|  |                     preferredBackground: undefined | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return ({ | ||||||
|                 title: Translations.T(pr.title, `${context}.presets[${i}].title`), |                 title: Translations.T(pr.title, `${context}.presets[${i}].title`), | ||||||
|                 tags: pr.tags.map(t => FromJSON.SimpleTag(t)), |                 tags: pr.tags.map(t => FromJSON.SimpleTag(t)), | ||||||
|                 description: Translations.T(pr.description, `${context}.presets[${i}].description`) |                 description: Translations.T(pr.description, `${context}.presets[${i}].description`), | ||||||
|             })) |                 preciseInput: pr.preciseInput | ||||||
|  |             }); | ||||||
|  |         }) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         /** Given a key, gets the corresponding property from the json (or the default if not found |         /** Given a key, gets the corresponding property from the json (or the default if not found | ||||||
|  |  | ||||||
|  | @ -217,6 +217,16 @@ export interface LayerConfigJson { | ||||||
|          * (The first sentence is until the first '.'-character in the description) |          * (The first sentence is until the first '.'-character in the description) | ||||||
|          */ |          */ | ||||||
|         description?: string | any, |         description?: string | any, | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * If set, the user will prompted to confirm the location before actually adding the data. | ||||||
|  |          * THis will be with a 'drag crosshair'-method. | ||||||
|  |          *  | ||||||
|  |          * If 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category. | ||||||
|  |          */ | ||||||
|  |         preciseInput?: true | { | ||||||
|  |             preferredBackground: "osmbasedmap" | "photo" | "historicphoto" | "map" | ||||||
|  |         } | ||||||
|     }[], |     }[], | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |  | ||||||
|  | @ -1,11 +1,13 @@ | ||||||
| import * as editorlayerindex from "../../assets/editor-layer-index.json" | import * as editorlayerindex from "../../assets/editor-layer-index.json" | ||||||
| import BaseLayer from "../../Models/BaseLayer"; | import BaseLayer from "../../Models/BaseLayer"; | ||||||
| import * as L from "leaflet"; | import * as L from "leaflet"; | ||||||
|  | import {TileLayer} from "leaflet"; | ||||||
| import * as X from "leaflet-providers"; | import * as X from "leaflet-providers"; | ||||||
| import {UIEventSource} from "../UIEventSource"; | import {UIEventSource} from "../UIEventSource"; | ||||||
| import {GeoOperations} from "../GeoOperations"; | import {GeoOperations} from "../GeoOperations"; | ||||||
| import {TileLayer} from "leaflet"; |  | ||||||
| import {Utils} from "../../Utils"; | import {Utils} from "../../Utils"; | ||||||
|  | import Loc from "../../Models/Loc"; | ||||||
|  | import {isBoolean} from "util"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Calculates which layers are available at the current location |  * Calculates which layers are available at the current location | ||||||
|  | @ -24,14 +26,16 @@ export default class AvailableBaseLayers { | ||||||
|                 false, false), |                 false, false), | ||||||
|             feature: null, |             feature: null, | ||||||
|             max_zoom: 19, |             max_zoom: 19, | ||||||
|             min_zoom: 0 |             min_zoom: 0, | ||||||
|  |             isBest: false, // This is a lie! Of course OSM is the best map! (But not in this context)
 | ||||||
|  |             category: "osmbasedmap" | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     public static layerOverview = AvailableBaseLayers.LoadRasterIndex().concat(AvailableBaseLayers.LoadProviderIndex()); |     public static layerOverview = AvailableBaseLayers.LoadRasterIndex().concat(AvailableBaseLayers.LoadProviderIndex()); | ||||||
|     public availableEditorLayers: UIEventSource<BaseLayer[]>; |     public availableEditorLayers: UIEventSource<BaseLayer[]>; | ||||||
| 
 | 
 | ||||||
|     constructor(location: UIEventSource<{ lat: number, lon: number, zoom: number }>) { |     constructor(location: UIEventSource<Loc>) { | ||||||
|         const self = this; |         const self = this; | ||||||
|         this.availableEditorLayers = |         this.availableEditorLayers = | ||||||
|             location.map( |             location.map( | ||||||
|  | @ -140,7 +144,9 @@ export default class AvailableBaseLayers { | ||||||
|                 min_zoom: props.min_zoom ?? 1, |                 min_zoom: props.min_zoom ?? 1, | ||||||
|                 name: props.name, |                 name: props.name, | ||||||
|                 layer: leafletLayer, |                 layer: leafletLayer, | ||||||
|                 feature: layer |                 feature: layer, | ||||||
|  |                 isBest: props.best ?? false, | ||||||
|  |                 category: props.category  | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|         return layers; |         return layers; | ||||||
|  | @ -152,15 +158,16 @@ export default class AvailableBaseLayers { | ||||||
|         function l(id: string, name: string): BaseLayer { |         function l(id: string, name: string): BaseLayer { | ||||||
|             try { |             try { | ||||||
|                 const layer: any = () => L.tileLayer.provider(id, undefined); |                 const layer: any = () => L.tileLayer.provider(id, undefined); | ||||||
|                 const baseLayer: BaseLayer = { |                 return { | ||||||
|                     feature: null, |                     feature: null, | ||||||
|                     id: id, |                     id: id, | ||||||
|                     name: name, |                     name: name, | ||||||
|                     layer: layer, |                     layer: layer, | ||||||
|                     min_zoom: layer.minzoom, |                     min_zoom: layer.minzoom, | ||||||
|                     max_zoom: layer.maxzoom |                     max_zoom: layer.maxzoom, | ||||||
|  |                     category: "osmbasedmap", | ||||||
|  |                     isBest: false | ||||||
|                 } |                 } | ||||||
|                 return baseLayer |  | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.error("Could not find provided layer", name, e); |                 console.error("Could not find provided layer", name, e); | ||||||
|                 return null; |                 return null; | ||||||
|  |  | ||||||
|  | @ -7,4 +7,6 @@ export default interface BaseLayer { | ||||||
|     max_zoom: number, |     max_zoom: number, | ||||||
|     min_zoom: number; |     min_zoom: number; | ||||||
|     feature: any, |     feature: any, | ||||||
|  |     isBest?: boolean, | ||||||
|  |     category?: "map" | "osmbasedmap" | "photo"  | "historicphoto" | string | ||||||
| } | } | ||||||
							
								
								
									
										7
									
								
								Svg.ts
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								Svg.ts
									
										
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -16,6 +16,9 @@ import {VariableUiElement} from "../Base/VariableUIElement"; | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle"; | ||||||
| import UserDetails from "../../Logic/Osm/OsmConnection"; | import UserDetails from "../../Logic/Osm/OsmConnection"; | ||||||
| import {Translation} from "../i18n/Translation"; | import {Translation} from "../i18n/Translation"; | ||||||
|  | import LocationInput from "../Input/LocationInput"; | ||||||
|  | import {InputElement} from "../Input/InputElement"; | ||||||
|  | import Loc from "../../Models/Loc"; | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
| * The SimpleAddUI is a single panel, which can have multiple states: | * The SimpleAddUI is a single panel, which can have multiple states: | ||||||
|  | @ -25,14 +28,18 @@ import {Translation} from "../i18n/Translation"; | ||||||
| * - A 'read your unread messages before adding a point' | * - A 'read your unread messages before adding a point' | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | /*private*/ | ||||||
| interface PresetInfo { | interface PresetInfo { | ||||||
|     description: string | Translation, |     description: string | Translation, | ||||||
|     name: string | BaseUIElement, |     name: string | BaseUIElement, | ||||||
|     icon: BaseUIElement, |     icon: () => BaseUIElement, | ||||||
|     tags: Tag[], |     tags: Tag[], | ||||||
|     layerToAddTo: { |     layerToAddTo: { | ||||||
|         layerDef: LayerConfig, |         layerDef: LayerConfig, | ||||||
|         isDisplayed: UIEventSource<boolean> |         isDisplayed: UIEventSource<boolean> | ||||||
|  |     }, | ||||||
|  |     preciseInput?: { | ||||||
|  |         preferredBackground?: string | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -50,13 +57,11 @@ export default class SimpleAddUI extends Toggle { | ||||||
|         ]); |         ]); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|          |  | ||||||
|         const selectedPreset = new UIEventSource<PresetInfo>(undefined); |         const selectedPreset = new UIEventSource<PresetInfo>(undefined); | ||||||
|         isShown.addCallback(_ => selectedPreset.setData(undefined)) // Clear preset selection when the UI is closed/opened
 |         isShown.addCallback(_ => selectedPreset.setData(undefined)) // Clear preset selection when the UI is closed/opened
 | ||||||
| 
 | 
 | ||||||
|         function createNewPoint(tags: any[]){ |         function createNewPoint(tags: any[], location: { lat: number, lon: number }) { | ||||||
|            const loc = State.state.LastClickLocation.data; |             let feature = State.state.changes.createElement(tags, location.lat, location.lon); | ||||||
|             let feature = State.state.changes.createElement(tags, loc.lat, loc.lon); |  | ||||||
|             State.state.selectedElement.setData(feature); |             State.state.selectedElement.setData(feature); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -68,8 +73,8 @@ export default class SimpleAddUI extends Toggle { | ||||||
|                         return presetsOverview |                         return presetsOverview | ||||||
|                     } |                     } | ||||||
|                     return SimpleAddUI.CreateConfirmButton(preset, |                     return SimpleAddUI.CreateConfirmButton(preset, | ||||||
|                         tags => { |                         (tags, location) => { | ||||||
|                             createNewPoint(tags) |                             createNewPoint(tags, location) | ||||||
|                             selectedPreset.setData(undefined) |                             selectedPreset.setData(undefined) | ||||||
|                         }, () => { |                         }, () => { | ||||||
|                             selectedPreset.setData(undefined) |                             selectedPreset.setData(undefined) | ||||||
|  | @ -103,20 +108,39 @@ export default class SimpleAddUI extends Toggle { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     private static CreateConfirmButton(preset: PresetInfo, |     private static CreateConfirmButton(preset: PresetInfo, | ||||||
|                                        confirm: (tags: any[]) => void,  |                                        confirm: (tags: any[], location: { lat: number, lon: number }) => void, | ||||||
|                                        cancel: () => void): BaseUIElement { |                                        cancel: () => void): BaseUIElement { | ||||||
| 
 | 
 | ||||||
|  |         let location = State.state.LastClickLocation; | ||||||
|  |         let preciseInput: InputElement<Loc> = undefined | ||||||
|  |         if (preset.preciseInput !== undefined) { | ||||||
|  |             preciseInput = new LocationInput({ | ||||||
|  |                 preferCategory: preset.preciseInput.preferredBackground ?? State.state.backgroundLayer, | ||||||
|  |                 centerLocation: | ||||||
|  |                     new UIEventSource({ | ||||||
|  |                         lat: location.data.lat, | ||||||
|  |                         lon: location.data.lon, | ||||||
|  |                         zoom: 19 | ||||||
|  |                     }) | ||||||
|  |             }) | ||||||
|  |             preciseInput.SetClass("h-32 rounded-xl overflow-hidden border border-gray").SetStyle("height: 12rem;") | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         const confirmButton = new SubtleButton(preset.icon, | 
 | ||||||
|  |         let confirmButton: BaseUIElement = new SubtleButton(preset.icon(), | ||||||
|             new Combine([ |             new Combine([ | ||||||
|                 Translations.t.general.add.addNew.Subs({category: preset.name}), |                 Translations.t.general.add.addNew.Subs({category: preset.name}), | ||||||
|                 Translations.t.general.add.warnVisibleForEveryone.Clone().SetClass("alert") |                 Translations.t.general.add.warnVisibleForEveryone.Clone().SetClass("alert") | ||||||
|             ]).SetClass("flex flex-col") |             ]).SetClass("flex flex-col") | ||||||
|         ).SetClass("font-bold break-words") |         ).SetClass("font-bold break-words") | ||||||
|             .onClick(() => confirm(preset.tags)); |             .onClick(() => { | ||||||
|  |                 confirm(preset.tags, (preciseInput?.GetValue() ?? location).data); | ||||||
|  |             }); | ||||||
|          |          | ||||||
|  |         if (preciseInput !== undefined) { | ||||||
|  |             confirmButton = new Combine([preciseInput, confirmButton]) | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         const openLayerControl = |         const openLayerControl = | ||||||
|             new SubtleButton( |             new SubtleButton( | ||||||
|  | @ -184,7 +208,7 @@ export default class SimpleAddUI extends Toggle { | ||||||
| 
 | 
 | ||||||
|         const tagInfo = SimpleAddUI.CreateTagInfoFor(preset, false); |         const tagInfo = SimpleAddUI.CreateTagInfoFor(preset, false); | ||||||
|         return new SubtleButton( |         return new SubtleButton( | ||||||
|             preset.icon, |             preset.icon(), | ||||||
|             new Combine([ |             new Combine([ | ||||||
|                 Translations.t.general.add.addNew.Subs({ |                 Translations.t.general.add.addNew.Subs({ | ||||||
|                     category: preset.name |                     category: preset.name | ||||||
|  | @ -209,14 +233,15 @@ export default class SimpleAddUI extends Toggle { | ||||||
|             for (const preset of presets) { |             for (const preset of presets) { | ||||||
| 
 | 
 | ||||||
|                 const tags = TagUtils.KVtoProperties(preset.tags ?? []); |                 const tags = TagUtils.KVtoProperties(preset.tags ?? []); | ||||||
|                 let icon: BaseUIElement = layer.layerDef.GenerateLeafletStyle(new UIEventSource<any>(tags), false).icon.html |                 let icon:() => BaseUIElement = () => layer.layerDef.GenerateLeafletStyle(new UIEventSource<any>(tags), false).icon.html | ||||||
|                     .SetClass("w-12 h-12 block relative"); |                     .SetClass("w-12 h-12 block relative"); | ||||||
|                 const presetInfo: PresetInfo = { |                 const presetInfo: PresetInfo = { | ||||||
|                     tags: preset.tags, |                     tags: preset.tags, | ||||||
|                     layerToAddTo: layer, |                     layerToAddTo: layer, | ||||||
|                     name: preset.title, |                     name: preset.title, | ||||||
|                     description: preset.description, |                     description: preset.description, | ||||||
|                     icon: icon |                     icon: icon, | ||||||
|  |                     preciseInput: preset.preciseInput | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 const button = SimpleAddUI.CreatePresetSelectButton(presetInfo); |                 const button = SimpleAddUI.CreatePresetSelectButton(presetInfo); | ||||||
|  |  | ||||||
							
								
								
									
										112
									
								
								UI/Input/LocationInput.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								UI/Input/LocationInput.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | ||||||
|  | import {InputElement} from "./InputElement"; | ||||||
|  | import Loc from "../../Models/Loc"; | ||||||
|  | import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
|  | import Minimap from "../Base/Minimap"; | ||||||
|  | import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"; | ||||||
|  | import BaseLayer from "../../Models/BaseLayer"; | ||||||
|  | import Combine from "../Base/Combine"; | ||||||
|  | import Svg from "../../Svg"; | ||||||
|  | 
 | ||||||
|  | export default class LocationInput extends InputElement<Loc> { | ||||||
|  | 
 | ||||||
|  |     IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); | ||||||
|  |     private _centerLocation: UIEventSource<Loc>; | ||||||
|  |     private readonly preferCategory; | ||||||
|  | 
 | ||||||
|  |     constructor(options?: { | ||||||
|  |         centerLocation?: UIEventSource<Loc>, | ||||||
|  |         preferCategory?: string | UIEventSource<string>, | ||||||
|  |     }) { | ||||||
|  |         super(); | ||||||
|  |         options = options ?? {} | ||||||
|  |         options.centerLocation = options.centerLocation ?? new UIEventSource<Loc>({lat: 0, lon: 0, zoom: 1}) | ||||||
|  |         this._centerLocation = options.centerLocation; | ||||||
|  | 
 | ||||||
|  |         if(typeof options.preferCategory === "string"){ | ||||||
|  |             options.preferCategory = new UIEventSource<string>(options.preferCategory); | ||||||
|  |         } | ||||||
|  |         this.preferCategory = options.preferCategory ?? new UIEventSource<string>(undefined) | ||||||
|  |         this.SetClass("block h-full") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     GetValue(): UIEventSource<Loc> { | ||||||
|  |         return this._centerLocation; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IsValid(t: Loc): boolean { | ||||||
|  |         return t !== undefined; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected InnerConstructElement(): HTMLElement { | ||||||
|  |         const layer: UIEventSource<BaseLayer> = new AvailableBaseLayers(this._centerLocation).availableEditorLayers.map(allLayers => { | ||||||
|  |                 // First float all 'best layers' to the top
 | ||||||
|  |                 allLayers.sort((a, b) => { | ||||||
|  |                         if (a.isBest && b.isBest) { | ||||||
|  |                             return 0; | ||||||
|  |                         } | ||||||
|  |                         if (!a.isBest) { | ||||||
|  |                             return 1 | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         return -1; | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |                 if (this.preferCategory) { | ||||||
|  |                     const self = this; | ||||||
|  |                     //Then sort all 'photo'-layers to the top. Stability of the sorting will force a 'best' photo layer on top
 | ||||||
|  |                     allLayers.sort((a, b) => { | ||||||
|  |                             const preferred = self.preferCategory.data | ||||||
|  |                             if (a.category === preferred && b.category === preferred) { | ||||||
|  |                                 return 0; | ||||||
|  |                             } | ||||||
|  |                             if (a.category !== preferred) { | ||||||
|  |                                 return 1 | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             return -1; | ||||||
|  |                         } | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |                 return allLayers[0] | ||||||
|  |             }, [this.preferCategory] | ||||||
|  |         ) | ||||||
|  |         layer.addCallbackAndRunD(layer => console.log(layer)) | ||||||
|  |         const map = new Minimap( | ||||||
|  |             { | ||||||
|  |                 location: this._centerLocation, | ||||||
|  |                 background: layer | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |         map.leafletMap.addCallbackAndRunD(leaflet => { | ||||||
|  |             console.log(leaflet.getBounds(), leaflet.getBounds().pad(0.15)) | ||||||
|  |             leaflet.setMaxBounds( | ||||||
|  |                 leaflet.getBounds().pad(0.15) | ||||||
|  |             ) | ||||||
|  |         }) | ||||||
|  | 
 | ||||||
|  |         layer.map(layer => { | ||||||
|  | 
 | ||||||
|  |             const leaflet = map.leafletMap.data | ||||||
|  |             if (leaflet === undefined || layer === undefined) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             leaflet.setMaxZoom(layer.max_zoom) | ||||||
|  |             leaflet.setMinZoom(layer.max_zoom - 3) | ||||||
|  |             leaflet.setZoom(layer.max_zoom - 1) | ||||||
|  | 
 | ||||||
|  |         }, [map.leafletMap]) | ||||||
|  |         return new Combine([ | ||||||
|  |             new Combine([ | ||||||
|  |                 Svg.crosshair_empty_ui() | ||||||
|  |                     .SetClass("block relative") | ||||||
|  |                     .SetStyle("left: -1.25rem; top: -1.25rem; width: 2.5rem; height: 2.5rem") | ||||||
|  |             ]).SetClass("block w-0 h-0 z-10 relative") | ||||||
|  |                 .SetStyle("background: rgba(255, 128, 128, 0.21); left: 50%; top: 50%"), | ||||||
|  |             map | ||||||
|  |                 .SetClass("z-0 relative block w-full h-full bg-gray-100") | ||||||
|  | 
 | ||||||
|  |         ]).ConstructElement(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -73,7 +73,10 @@ | ||||||
|       }, |       }, | ||||||
|       "tags": [ |       "tags": [ | ||||||
|         "amenity=public_bookcase" |         "amenity=public_bookcase" | ||||||
|       ] |       ], | ||||||
|  |       "preciseInput": { | ||||||
|  |         "preferredBackground": "photo" | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   ], |   ], | ||||||
|   "tagRenderings": [ |   "tagRenderings": [ | ||||||
|  |  | ||||||
							
								
								
									
										83
									
								
								assets/svg/crosshair-empty.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								assets/svg/crosshair-empty.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,83 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  | 
 | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="100" | ||||||
|  |    height="100" | ||||||
|  |    viewBox="0 0 26.458333 26.458334" | ||||||
|  |    version="1.1" | ||||||
|  |    id="svg8" | ||||||
|  |    inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)" | ||||||
|  |    sodipodi:docname="crosshair-empty.svg"> | ||||||
|  |   <defs | ||||||
|  |      id="defs2" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#ffffff" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0.0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="5.6568542" | ||||||
|  |      inkscape:cx="22.669779" | ||||||
|  |      inkscape:cy="52.573519" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="g848" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:guide-bbox="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="999" | ||||||
|  |      inkscape:window-x="0" | ||||||
|  |      inkscape:window-y="0" | ||||||
|  |      inkscape:window-maximized="1"> | ||||||
|  |     <sodipodi:guide | ||||||
|  |        position="13.229167,23.859748" | ||||||
|  |        orientation="1,0" | ||||||
|  |        id="guide815" | ||||||
|  |        inkscape:locked="false" /> | ||||||
|  |     <sodipodi:guide | ||||||
|  |        position="14.944824,13.229167" | ||||||
|  |        orientation="0,1" | ||||||
|  |        id="guide817" | ||||||
|  |        inkscape:locked="false" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata5"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title /> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-270.54165)"> | ||||||
|  |     <g | ||||||
|  |        id="g848"> | ||||||
|  |       <path | ||||||
|  |          style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#5555ec;fill-opacity:0.98823529;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.26458333;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" | ||||||
|  |          d="m 13.162109,273.57617 c -5.6145729,0 -10.1933596,4.58074 -10.193359,10.19531 -6e-7,5.61458 4.5787861,10.19336 10.193359,10.19336 5.614574,0 10.195313,-4.57878 10.195313,-10.19336 0,-5.61457 -4.580739,-10.19531 -10.195313,-10.19531 z m 0,2.64649 c 4.184659,0 7.548829,3.36417 7.548829,7.54882 0,4.18466 -3.36417,7.54883 -7.548829,7.54883 -4.1846584,0 -7.546875,-3.36417 -7.5468746,-7.54883 -4e-7,-4.18465 3.3622162,-7.54882 7.5468746,-7.54882 z" | ||||||
|  |          id="path815" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |       <path | ||||||
|  |          id="path839" | ||||||
|  |          style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#0055ec;fill-opacity:0.98823529;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.26458333;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" | ||||||
|  |          d="m 13.212891,286.88672 a 1.0487243,1.0487243 0 0 0 -1.033203,1.06445 v 7.94922 a 1.048828,1.048828 0 1 0 2.097656,0 v -7.94922 a 1.0487243,1.0487243 0 0 0 -1.064453,-1.06445 z m 0,-16.36914 a 1.0487243,1.0487243 0 0 0 -1.033203,1.0625 v 7.94922 a 1.048828,1.048828 0 1 0 2.097656,0 v -7.94922 a 1.0487243,1.0487243 0 0 0 -1.064453,-1.0625 z m 4.246093,12.20508 a 1.048825,1.048825 0 1 0 0,2.09765 h 7.949219 a 1.048825,1.048825 0 1 0 0,-2.09765 z m -16.4179684,0 a 1.048825,1.048825 0 1 0 0,2.09765 h 7.9492188 a 1.048825,1.048825 0 1 0 0,-2.09765 z" /> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 5.6 KiB | 
							
								
								
									
										29
									
								
								test.ts
									
										
									
									
									
								
							
							
						
						
									
										29
									
								
								test.ts
									
										
									
									
									
								
							|  | @ -7,6 +7,9 @@ import {UIEventSource} from "./Logic/UIEventSource"; | ||||||
| import {Tag} from "./Logic/Tags/Tag"; | import {Tag} from "./Logic/Tags/Tag"; | ||||||
| import {QueryParameters} from "./Logic/Web/QueryParameters"; | import {QueryParameters} from "./Logic/Web/QueryParameters"; | ||||||
| import {Translation} from "./UI/i18n/Translation"; | import {Translation} from "./UI/i18n/Translation"; | ||||||
|  | import LocationInput from "./UI/Input/LocationInput"; | ||||||
|  | import Loc from "./Models/Loc"; | ||||||
|  | import {VariableUiElement} from "./UI/Base/VariableUIElement"; | ||||||
| /*import ValidatedTextField from "./UI/Input/ValidatedTextField"; | /*import ValidatedTextField from "./UI/Input/ValidatedTextField"; | ||||||
| import Combine from "./UI/Base/Combine"; | import Combine from "./UI/Base/Combine"; | ||||||
| import {VariableUiElement} from "./UI/Base/VariableUIElement"; | import {VariableUiElement} from "./UI/Base/VariableUIElement"; | ||||||
|  | @ -148,19 +151,15 @@ function TestMiniMap() { | ||||||
|     featureSource.ping() |     featureSource.ping() | ||||||
| } | } | ||||||
| //*/
 | //*/
 | ||||||
| QueryParameters.GetQueryParameter("test", "true").setData("true") | 
 | ||||||
| State.state= new State(undefined) | const li = new LocationInput({ | ||||||
| const id = "node/5414688303" |     preferCategory:"photo", | ||||||
| State.state.allElements.addElementById(id, new UIEventSource<any>({id: id})) |     centerLocation: | ||||||
| new Combine([ |         new UIEventSource<Loc>({ | ||||||
|     new DeleteWizard(id, { |             lat: 51.21576, lon: 3.22001, zoom: 19 | ||||||
|         noDeleteOptions: [ |  | ||||||
|             { |  | ||||||
|                 if:[ new Tag("access","private")], |  | ||||||
|                 then: new Translation({ |  | ||||||
|                     en: "Very private! Delete now or me send lawfull lawyer" |  | ||||||
|         }) |         }) | ||||||
|             } | }) | ||||||
|         ] |     li.SetStyle("height: 20rem") | ||||||
|     }), |         .AttachTo("maindiv") | ||||||
| ]).AttachTo("maindiv") | 
 | ||||||
|  | new VariableUiElement(li.GetValue().map(v => JSON.stringify(v, null, "  "))).AttachTo("extradiv") | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue