forked from MapComplete/MapComplete
		
	Merge branch 'develop' into alpha
This commit is contained in:
		
						commit
						3be0dbd22f
					
				
					 8 changed files with 3754 additions and 3629 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -17,3 +17,4 @@ missing_translations.txt | |||
| .DS_Store | ||||
| Svg.ts | ||||
| data/ | ||||
| Folder.DotSettings.user | ||||
|  |  | |||
							
								
								
									
										100
									
								
								Logic/Actors/SelectedElementTagsUpdater.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								Logic/Actors/SelectedElementTagsUpdater.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| /** | ||||
|  * This actor will download the latest version of the selected element from OSM and update the tags if necessary. | ||||
|  */ | ||||
| import {UIEventSource} from "../UIEventSource"; | ||||
| import {ElementStorage} from "../ElementStorage"; | ||||
| import {Changes} from "../Osm/Changes"; | ||||
| import {OsmObject} from "../Osm/OsmObject"; | ||||
| import {OsmConnection} from "../Osm/OsmConnection"; | ||||
| 
 | ||||
| export default class SelectedElementTagsUpdater { | ||||
| 
 | ||||
|     constructor(state: { | ||||
|         selectedElement: UIEventSource<any>, | ||||
|         allElements: ElementStorage, | ||||
|         changes: Changes, | ||||
|         osmConnection: OsmConnection | ||||
|     }) { | ||||
| 
 | ||||
| 
 | ||||
|         state.osmConnection.isLoggedIn.addCallbackAndRun(isLoggedIn => { | ||||
|             if(isLoggedIn){ | ||||
|                 SelectedElementTagsUpdater.installCallback(state) | ||||
|                 return true; | ||||
|             } | ||||
|         }) | ||||
| 
 | ||||
|     } | ||||
|      | ||||
|     private static installCallback(state: { | ||||
|         selectedElement: UIEventSource<any>, | ||||
|         allElements: ElementStorage, | ||||
|         changes: Changes, | ||||
|         osmConnection: OsmConnection | ||||
|     }) { | ||||
| 
 | ||||
| 
 | ||||
|         state.selectedElement.addCallbackAndRunD(s => { | ||||
|             const id = s.properties?.id | ||||
|             OsmObject.DownloadObjectAsync(id).then(obj => { | ||||
|                 SelectedElementTagsUpdater.applyUpdate(state, obj, id) | ||||
|             }).catch(e => { | ||||
|                 console.error("Could not update tags of ", id, "due to", e) | ||||
|             }) | ||||
|         }); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private static applyUpdate(state: { | ||||
|                                    selectedElement: UIEventSource<any>, | ||||
|                                    allElements: ElementStorage, | ||||
|                                    changes: Changes, | ||||
|                                    osmConnection: OsmConnection | ||||
|                                }, obj: OsmObject, id: string | ||||
|     ) { | ||||
|         const pendingChanges = state.changes.pendingChanges.data | ||||
|             .filter(change => change.type === obj.type && change.id === obj.id) | ||||
|             .filter(change => change.tags !== undefined); | ||||
|         const latestTags = obj.tags | ||||
|         console.log("Applying updates of ", id, " got tags", latestTags, "and still have to apply changes: ", pendingChanges) | ||||
| 
 | ||||
|         for (const pendingChange of pendingChanges) { | ||||
|             const tagChanges = pendingChange.tags; | ||||
|             for (const tagChange of tagChanges) { | ||||
|                 const key = tagChange.k | ||||
|                 const v = tagChange.v | ||||
|                 if (v === undefined || v === "") { | ||||
|                     delete latestTags[key] | ||||
|                 } else { | ||||
|                     latestTags[key] = v | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // With the changes applied, we merge them onto the upstream object
 | ||||
|         let somethingChanged = false; | ||||
|         const currentTagsSource = state.allElements.getEventSourceById(id); | ||||
|         const currentTags = currentTagsSource.data | ||||
|         for (const key in latestTags) { | ||||
|             let osmValue = latestTags[key] | ||||
|              | ||||
|             if(typeof osmValue === "number"){ | ||||
|                 osmValue = ""+osmValue | ||||
|             } | ||||
|              | ||||
|             const localValue = currentTags[key] | ||||
|             if (localValue !== osmValue) { | ||||
|                 console.log("Local value:", localValue, "upstream", osmValue) | ||||
|                 somethingChanged = true; | ||||
|                 currentTags[key] = osmValue | ||||
|             } | ||||
|         } | ||||
|         if (somethingChanged) { | ||||
|             console.log("Detected upstream changes to the object when opening it, updating...") | ||||
|             currentTagsSource.ping() | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -7,12 +7,14 @@ export default class ImgurUploader { | |||
|     public readonly failed: UIEventSource<string[]> = new UIEventSource<string[]>([]); | ||||
|     public readonly success: UIEventSource<string[]> = new UIEventSource<string[]>([]); | ||||
|     private readonly _handleSuccessUrl: (string) => void; | ||||
|      | ||||
|     public maxFileSizeInMegabytes = 10; | ||||
| 
 | ||||
|     constructor(handleSuccessUrl: (string) => void) { | ||||
|         this._handleSuccessUrl = handleSuccessUrl; | ||||
|     } | ||||
| 
 | ||||
|     public uploadMany(title: string, description: string, files: FileList) { | ||||
|     public uploadMany(title: string, description: string, files: FileList): void { | ||||
|         for (let i = 0; i < files.length; i++) { | ||||
|             this.queue.data.push(files.item(i).name) | ||||
|         } | ||||
|  |  | |||
|  | @ -36,6 +36,8 @@ export interface ChangeDescription { | |||
|     /** | ||||
|      * All changes to tags | ||||
|      * v = "" or v = undefined to erase this tag | ||||
|      *  | ||||
|      * Note that this list will only contain the _changes_ to the tags, not the full set of tags | ||||
|      */ | ||||
|     tags?: { k: string, v: string }[], | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										3
									
								
								State.ts
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								State.ts
									
										
									
									
									
								
							|  | @ -18,6 +18,7 @@ import FilteredLayer from "./Models/FilteredLayer"; | |||
| import ChangeToElementsActor from "./Logic/Actors/ChangeToElementsActor"; | ||||
| import LayoutConfig from "./Models/ThemeConfig/LayoutConfig"; | ||||
| import {BBox} from "./Logic/BBox"; | ||||
| import SelectedElementTagsUpdater from "./Logic/Actors/SelectedElementTagsUpdater"; | ||||
| 
 | ||||
| /** | ||||
|  * Contains the global state: a bunch of UI-event sources | ||||
|  | @ -376,6 +377,8 @@ export default class State { | |||
|         new ChangeToElementsActor(this.changes, this.allElements) | ||||
| 
 | ||||
|         new PendingChangesUploader(this.changes, this.selectedElement); | ||||
|          | ||||
|         new SelectedElementTagsUpdater(this) | ||||
| 
 | ||||
|         this.mangroveIdentity = new MangroveIdentity( | ||||
|             this.osmConnection.GetLongPreference("identity", "mangrove") | ||||
|  |  | |||
|  | @ -39,7 +39,10 @@ export class ImageUploadFlow extends Toggle { | |||
|                     } | ||||
|                 ))) | ||||
|         }) | ||||
| 
 | ||||
|          | ||||
|         uploader.queue.addCallbackD(q => console.log("Image upload queue is ", q)) | ||||
|         uploader.failed.addCallbackD(q => console.log("Image upload fail list is ", q)) | ||||
|         uploader.success.addCallbackD(q => console.log("Image upload success list is ", q)) | ||||
| 
 | ||||
|         const licensePicker = new LicensePicker() | ||||
| 
 | ||||
|  | @ -58,10 +61,23 @@ export class ImageUploadFlow extends Toggle { | |||
| 
 | ||||
|         const fileSelector = new FileSelectorButton(label) | ||||
|         fileSelector.GetValue().addCallback(filelist => { | ||||
|             if (filelist === undefined) { | ||||
|             if (filelist === undefined || filelist.length === 0) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             for (var i = 0; i < filelist.length; i++) { | ||||
|                 const sizeInBytes=  filelist[i].size | ||||
|                 console.log(filelist[i].name + " has a size of " + sizeInBytes + " Bytes"); | ||||
|                 if(sizeInBytes > uploader.maxFileSizeInMegabytes * 1000000){ | ||||
|                     alert(Translations.t.image.toBig.Subs({ | ||||
|                         actual_size: (Math.floor(sizeInBytes / 1000000)) + "MB", | ||||
|                         max_size: uploader.maxFileSizeInMegabytes+"MB" | ||||
|                     }).txt) | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             console.log("Received images from the user, starting upload") | ||||
|             const license = licensePicker.GetValue()?.data ?? "CC0" | ||||
| 
 | ||||
|  | @ -77,7 +93,7 @@ export class ImageUploadFlow extends Toggle { | |||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             const title = matchingLayer?.title?.GetRenderValue(tags)?.ConstructElement().innerText ?? tags.name ?? "Unknown area"; | ||||
|             const title = matchingLayer?.title?.GetRenderValue(tags)?.ConstructElement()?.innerText ?? tags.name ?? "Unknown area"; | ||||
|             const description = [ | ||||
|                 "author:" + State.state.osmConnection.userDetails.data.name, | ||||
|                 "license:" + license, | ||||
|  | @ -92,10 +108,10 @@ export class ImageUploadFlow extends Toggle { | |||
|         const uploadStateUi = new UploadFlowStateUI(uploader.queue, uploader.failed, uploader.success) | ||||
| 
 | ||||
|         const uploadFlow: BaseUIElement = new Combine([ | ||||
|             uploadStateUi, | ||||
|             fileSelector, | ||||
|             Translations.t.image.respectPrivacy.Clone().SetStyle("font-size:small;"), | ||||
|             licensePicker, | ||||
|             uploadStateUi | ||||
|             licensePicker | ||||
|         ]).SetClass("flex flex-col image-upload-flow mt-4 mb-8 text-center") | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -13,7 +13,8 @@ | |||
|         "uploadDone": "<span class='thanks'>Your picture has been added. Thanks for helping out!</span>", | ||||
|         "dontDelete": "Cancel", | ||||
|         "doDelete": "Remove image", | ||||
|         "isDeleted": "Deleted" | ||||
|         "isDeleted": "Deleted", | ||||
|         "toBig": "Your image is too large as it is {actual_size}. Please use images of at most {max_size}" | ||||
|     }, | ||||
|     "centerMessage": { | ||||
|         "loadingData": "Loading data…", | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue