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, | ||||
|         tags: Tag[], | ||||
|         description?: Translation, | ||||
|         preciseInput?: {preferredBackground?: string} | ||||
|     }[]; | ||||
| 
 | ||||
|     tagRenderings: TagRenderingConfig []; | ||||
|  | @ -130,12 +131,19 @@ export default class LayerConfig { | |||
|         this.minzoom = json.minzoom ?? 0; | ||||
|         this.maxzoom = json.maxzoom ?? 1000; | ||||
|         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`), | ||||
|                 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 | ||||
|  |  | |||
|  | @ -217,6 +217,16 @@ export interface LayerConfigJson { | |||
|          * (The first sentence is until the first '.'-character in the description) | ||||
|          */ | ||||
|         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 BaseLayer from "../../Models/BaseLayer"; | ||||
| import * as L from "leaflet"; | ||||
| import {TileLayer} from "leaflet"; | ||||
| import * as X from "leaflet-providers"; | ||||
| import {UIEventSource} from "../UIEventSource"; | ||||
| import {GeoOperations} from "../GeoOperations"; | ||||
| import {TileLayer} from "leaflet"; | ||||
| import {Utils} from "../../Utils"; | ||||
| import Loc from "../../Models/Loc"; | ||||
| import {isBoolean} from "util"; | ||||
| 
 | ||||
| /** | ||||
|  * Calculates which layers are available at the current location | ||||
|  | @ -24,14 +26,16 @@ export default class AvailableBaseLayers { | |||
|                 false, false), | ||||
|             feature: null, | ||||
|             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 availableEditorLayers: UIEventSource<BaseLayer[]>; | ||||
| 
 | ||||
|     constructor(location: UIEventSource<{ lat: number, lon: number, zoom: number }>) { | ||||
|     constructor(location: UIEventSource<Loc>) { | ||||
|         const self = this; | ||||
|         this.availableEditorLayers = | ||||
|             location.map( | ||||
|  | @ -140,7 +144,9 @@ export default class AvailableBaseLayers { | |||
|                 min_zoom: props.min_zoom ?? 1, | ||||
|                 name: props.name, | ||||
|                 layer: leafletLayer, | ||||
|                 feature: layer | ||||
|                 feature: layer, | ||||
|                 isBest: props.best ?? false, | ||||
|                 category: props.category  | ||||
|             }); | ||||
|         } | ||||
|         return layers; | ||||
|  | @ -152,15 +158,16 @@ export default class AvailableBaseLayers { | |||
|         function l(id: string, name: string): BaseLayer { | ||||
|             try { | ||||
|                 const layer: any = () => L.tileLayer.provider(id, undefined); | ||||
|                 const baseLayer: BaseLayer = { | ||||
|                 return { | ||||
|                     feature: null, | ||||
|                     id: id, | ||||
|                     name: name, | ||||
|                     layer: layer, | ||||
|                     min_zoom: layer.minzoom, | ||||
|                     max_zoom: layer.maxzoom | ||||
|                     max_zoom: layer.maxzoom, | ||||
|                     category: "osmbasedmap", | ||||
|                     isBest: false | ||||
|                 } | ||||
|                 return baseLayer | ||||
|             } catch (e) { | ||||
|                 console.error("Could not find provided layer", name, e); | ||||
|                 return null; | ||||
|  |  | |||
|  | @ -7,4 +7,6 @@ export default interface BaseLayer { | |||
|     max_zoom: number, | ||||
|     min_zoom: number; | ||||
|     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 UserDetails from "../../Logic/Osm/OsmConnection"; | ||||
| 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: | ||||
|  | @ -25,14 +28,18 @@ import {Translation} from "../i18n/Translation"; | |||
| * - A 'read your unread messages before adding a point' | ||||
|  */ | ||||
| 
 | ||||
| /*private*/ | ||||
| interface PresetInfo { | ||||
|     description: string | Translation, | ||||
|     name: string | BaseUIElement, | ||||
|     icon: BaseUIElement, | ||||
|     icon: () => BaseUIElement, | ||||
|     tags: Tag[], | ||||
|     layerToAddTo: { | ||||
|         layerDef: LayerConfig, | ||||
|         isDisplayed: UIEventSource<boolean> | ||||
|     }, | ||||
|     preciseInput?: { | ||||
|         preferredBackground?: string | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -50,13 +57,11 @@ export default class SimpleAddUI extends Toggle { | |||
|         ]); | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
|         const selectedPreset = new UIEventSource<PresetInfo>(undefined); | ||||
|         isShown.addCallback(_ => selectedPreset.setData(undefined)) // Clear preset selection when the UI is closed/opened
 | ||||
| 
 | ||||
|         function createNewPoint(tags: any[]){ | ||||
|            const loc = State.state.LastClickLocation.data; | ||||
|             let feature = State.state.changes.createElement(tags, loc.lat, loc.lon); | ||||
|         function createNewPoint(tags: any[], location: { lat: number, lon: number }) { | ||||
|             let feature = State.state.changes.createElement(tags, location.lat, location.lon); | ||||
|             State.state.selectedElement.setData(feature); | ||||
|         } | ||||
| 
 | ||||
|  | @ -68,8 +73,8 @@ export default class SimpleAddUI extends Toggle { | |||
|                         return presetsOverview | ||||
|                     } | ||||
|                     return SimpleAddUI.CreateConfirmButton(preset, | ||||
|                         tags => { | ||||
|                             createNewPoint(tags) | ||||
|                         (tags, location) => { | ||||
|                             createNewPoint(tags, location) | ||||
|                             selectedPreset.setData(undefined) | ||||
|                         }, () => { | ||||
|                             selectedPreset.setData(undefined) | ||||
|  | @ -86,7 +91,7 @@ export default class SimpleAddUI extends Toggle { | |||
|                         addUi, | ||||
|                         State.state.layerUpdater.runningQuery | ||||
|                     ), | ||||
|                     Translations.t.general.add.zoomInFurther.Clone().SetClass("alert")                    , | ||||
|                     Translations.t.general.add.zoomInFurther.Clone().SetClass("alert"), | ||||
|                     State.state.locationControl.map(loc => loc.zoom >= Constants.userJourney.minZoomLevelToAddNewPoints) | ||||
|                 ), | ||||
|                 readYourMessages, | ||||
|  | @ -103,20 +108,39 @@ export default class SimpleAddUI extends Toggle { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     private static CreateConfirmButton(preset: PresetInfo, | ||||
|                                        confirm: (tags: any[]) => void,  | ||||
|                                        confirm: (tags: any[], location: { lat: number, lon: number }) => void, | ||||
|                                        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([ | ||||
|                 Translations.t.general.add.addNew.Subs({category: preset.name}), | ||||
|                 Translations.t.general.add.warnVisibleForEveryone.Clone().SetClass("alert") | ||||
|             ]).SetClass("flex flex-col") | ||||
|         ).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 = | ||||
|             new SubtleButton( | ||||
|  | @ -129,7 +153,7 @@ export default class SimpleAddUI extends Toggle { | |||
|                 ]) | ||||
|             ) | ||||
| 
 | ||||
|             .onClick(() => State.state.layerControlIsOpened.setData(true)) | ||||
|                 .onClick(() => State.state.layerControlIsOpened.setData(true)) | ||||
| 
 | ||||
|         const openLayerOrConfirm = new Toggle( | ||||
|             confirmButton, | ||||
|  | @ -140,12 +164,12 @@ export default class SimpleAddUI extends Toggle { | |||
| 
 | ||||
|         const cancelButton = new SubtleButton(Svg.close_ui(), | ||||
|             Translations.t.general.cancel | ||||
|         ).onClick(cancel        ) | ||||
|         ).onClick(cancel) | ||||
| 
 | ||||
|         return new Combine([ | ||||
|             Translations.t.general.add.confirmIntro.Subs({title: preset.name}), | ||||
|             State.state.osmConnection.userDetails.data.dryRun ? | ||||
|                 Translations.t.general.testing.Clone().SetClass("alert") : undefined           ,  | ||||
|                 Translations.t.general.testing.Clone().SetClass("alert") : undefined, | ||||
|             openLayerOrConfirm, | ||||
|             cancelButton, | ||||
|             preset.description, | ||||
|  | @ -180,11 +204,11 @@ export default class SimpleAddUI extends Toggle { | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private static CreatePresetSelectButton(preset: PresetInfo){ | ||||
|     private static CreatePresetSelectButton(preset: PresetInfo) { | ||||
| 
 | ||||
|         const tagInfo =SimpleAddUI.CreateTagInfoFor(preset, false); | ||||
|         const tagInfo = SimpleAddUI.CreateTagInfoFor(preset, false); | ||||
|         return new SubtleButton( | ||||
|             preset.icon, | ||||
|             preset.icon(), | ||||
|             new Combine([ | ||||
|                 Translations.t.general.add.addNew.Subs({ | ||||
|                     category: preset.name | ||||
|  | @ -195,13 +219,13 @@ export default class SimpleAddUI extends Toggle { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
| /* | ||||
| * Generates the list with all the buttons.*/ | ||||
|     /* | ||||
|     * Generates the list with all the buttons.*/ | ||||
|     private static CreatePresetButtons(selectedPreset: UIEventSource<PresetInfo>): BaseUIElement { | ||||
|         const allButtons = []; | ||||
|         for (const layer of State.state.filteredLayers.data) { | ||||
| 
 | ||||
|             if(layer.isDisplayed.data === false && State.state.featureSwitchLayers){ | ||||
|             if (layer.isDisplayed.data === false && State.state.featureSwitchLayers) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|  | @ -209,14 +233,15 @@ export default class SimpleAddUI extends Toggle { | |||
|             for (const preset of presets) { | ||||
| 
 | ||||
|                 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"); | ||||
|                 const presetInfo: PresetInfo = { | ||||
|                     tags: preset.tags, | ||||
|                     layerToAddTo: layer, | ||||
|                     name: preset.title, | ||||
|                     description: preset.description, | ||||
|                     icon: icon | ||||
|                     icon: icon, | ||||
|                     preciseInput: preset.preciseInput | ||||
|                 } | ||||
| 
 | ||||
|                 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": [ | ||||
|         "amenity=public_bookcase" | ||||
|       ] | ||||
|       ], | ||||
|       "preciseInput": { | ||||
|         "preferredBackground": "photo" | ||||
|       } | ||||
|     } | ||||
|   ], | ||||
|   "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 | 
							
								
								
									
										31
									
								
								test.ts
									
										
									
									
									
								
							
							
						
						
									
										31
									
								
								test.ts
									
										
									
									
									
								
							|  | @ -7,6 +7,9 @@ import {UIEventSource} from "./Logic/UIEventSource"; | |||
| import {Tag} from "./Logic/Tags/Tag"; | ||||
| import {QueryParameters} from "./Logic/Web/QueryParameters"; | ||||
| 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 Combine from "./UI/Base/Combine"; | ||||
| import {VariableUiElement} from "./UI/Base/VariableUIElement"; | ||||
|  | @ -148,19 +151,15 @@ function TestMiniMap() { | |||
|     featureSource.ping() | ||||
| } | ||||
| //*/
 | ||||
| QueryParameters.GetQueryParameter("test", "true").setData("true") | ||||
| State.state= new State(undefined) | ||||
| const id = "node/5414688303" | ||||
| State.state.allElements.addElementById(id, new UIEventSource<any>({id: id})) | ||||
| new Combine([ | ||||
|     new DeleteWizard(id, { | ||||
|         noDeleteOptions: [ | ||||
|             { | ||||
|                 if:[ new Tag("access","private")], | ||||
|                 then: new Translation({ | ||||
|                     en: "Very private! Delete now or me send lawfull lawyer" | ||||
|                 }) | ||||
|             } | ||||
|         ] | ||||
|     }), | ||||
| ]).AttachTo("maindiv") | ||||
| 
 | ||||
| const li = new LocationInput({ | ||||
|     preferCategory:"photo", | ||||
|     centerLocation: | ||||
|         new UIEventSource<Loc>({ | ||||
|             lat: 51.21576, lon: 3.22001, zoom: 19 | ||||
|         }) | ||||
| }) | ||||
|     li.SetStyle("height: 20rem") | ||||
|         .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