forked from MapComplete/MapComplete
		
	Only upload changes after 30s, on focus loss or on closing of the popup - this should improve #162 already a lot
This commit is contained in:
		
							parent
							
								
									3fb2b9adab
								
							
						
					
					
						commit
						df483786b3
					
				
					 4 changed files with 88 additions and 7 deletions
				
			
		
							
								
								
									
										54
									
								
								Logic/Actors/PendingChangesUploader.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Logic/Actors/PendingChangesUploader.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| import {Changes} from "../Osm/Changes"; | ||||
| import Constants from "../../Models/Constants"; | ||||
| import {UIEventSource} from "../UIEventSource"; | ||||
| 
 | ||||
| export default class PendingChangesUploader{ | ||||
|      | ||||
|     private lastChange : Date; | ||||
|      | ||||
|     constructor(changes: Changes, selectedFeature: UIEventSource<any>) { | ||||
|         const self = this; | ||||
|         this.lastChange = new Date(); | ||||
|         changes.pending.addCallback(() => { | ||||
|             self.lastChange = new Date(); | ||||
|              | ||||
|             window.setTimeout(() => { | ||||
|                 const diff = (new Date().getTime() - self.lastChange.getTime()) / 1000; | ||||
|                 if(Constants.updateTimeoutSec >= diff - 1){ | ||||
|                     changes.flushChanges("Flushing changes due to timeout"); | ||||
|                 } | ||||
|             }, Constants.updateTimeoutSec * 1000); | ||||
|         }); | ||||
|          | ||||
|          | ||||
|         selectedFeature | ||||
|             .stabilized(10000) | ||||
|             .addCallback(feature => { | ||||
|             if(feature === undefined){ | ||||
|                 // The popup got closed - we flush
 | ||||
|                 changes.flushChanges("Flushing changes due to popup closed"); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         document.addEventListener('mouseout', e => { | ||||
|             // @ts-ignore
 | ||||
|             if (!e.toElement && !e.relatedTarget) { | ||||
|                 changes.flushChanges("Flushing changes due to focus lost"); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         window.onbeforeunload = function(e){  | ||||
|              | ||||
|             if(changes.pending.data.length == 0){ | ||||
|                 return; | ||||
|             } | ||||
|             changes.flushChanges("onbeforeunload - probably closing or something similar"); | ||||
|             e.preventDefault(); | ||||
|             return "Saving your last changes..." | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
|      | ||||
|      | ||||
|      | ||||
| } | ||||
|  | @ -12,9 +12,17 @@ import FeatureSource from "../FeatureSource/FeatureSource"; | |||
|  */ | ||||
| export class Changes implements FeatureSource{ | ||||
| 
 | ||||
|     /** | ||||
|      * The newly created points, as a FeatureSource | ||||
|      */ | ||||
|     public features = new UIEventSource<{feature: any, freshness: Date}[]>([]); | ||||
|      | ||||
|     private static _nextId = -1; // Newly assigned ID's are negative
 | ||||
|     /** | ||||
|      * All the pending changes | ||||
|      */ | ||||
|     public readonly pending: UIEventSource<{ elementId: string, key: string, value: string }[]> =  | ||||
|         new UIEventSource<{elementId: string; key: string; value: string}[]>([]); | ||||
| 
 | ||||
|     /** | ||||
|      * Adds a change to the pending changes | ||||
|  | @ -39,6 +47,8 @@ export class Changes implements FeatureSource{ | |||
|         return {k: key, v: value}; | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|      | ||||
|     addTag(elementId: string, tagsFilter: TagsFilter, | ||||
|            tags?: UIEventSource<any>) { | ||||
|         const changes = this.tagToChange(tagsFilter); | ||||
|  | @ -47,21 +57,30 @@ export class Changes implements FeatureSource{ | |||
|         } | ||||
|         const eventSource = tags ?? State.state?.allElements.getEventSourceById(elementId); | ||||
|         const elementTags = eventSource.data; | ||||
|         const pending: { elementId: string, key: string, value: string }[] = []; | ||||
|         for (const change of changes) { | ||||
|             if (elementTags[change.k] !== change.v) { | ||||
|                 elementTags[change.k] = change.v; | ||||
|                 pending.push({elementId: elementTags.id, key: change.k, value: change.v}); | ||||
|                 this.pending.data.push({elementId: elementTags.id, key: change.k, value: change.v}); | ||||
|             } | ||||
|         } | ||||
|         if (pending.length === 0) { | ||||
|             return; | ||||
|         } | ||||
|         console.log("Sending ping", eventSource) | ||||
|         this.pending.ping(); | ||||
|         eventSource.ping(); | ||||
|         this.uploadAll([], pending); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Uploads all the pending changes in one go. | ||||
|      * Triggered by the 'PendingChangeUploader'-actor in Actors | ||||
|      */ | ||||
|     public flushChanges(flushreason: string = undefined){ | ||||
|         if(this.pending.data.length === 0){ | ||||
|             return; | ||||
|         } | ||||
|         if(flushreason !== undefined){ | ||||
|             console.log(flushreason) | ||||
|         } | ||||
|         this.uploadAll([], this.pending.data); | ||||
|         this.pending.setData([]); | ||||
|     } | ||||
|     /** | ||||
|      * Create a new node element at the given lat/long. | ||||
|      * An internal OsmObject is created to upload later on, a geojson represention is returned. | ||||
|  |  | |||
|  | @ -17,6 +17,11 @@ export default class Constants { | |||
|         addNewPointWithUnreadMessagesUnlock: 500, | ||||
|         minZoomLevelToAddNewPoints: (Constants.isRetina() ? 18 : 19) | ||||
|     }; | ||||
|     /** | ||||
|      * Used by 'PendingChangesUploader', which waits this amount of seconds to upload changes. | ||||
|      * (Note that pendingChanges might upload sooner if the popup is closed or similar) | ||||
|      */ | ||||
|     static updateTimeoutSec: number = 30; | ||||
| 
 | ||||
|     private static isRetina(): boolean { | ||||
|         if (Utils.runningFromConsole) { | ||||
|  |  | |||
							
								
								
									
										3
									
								
								State.ts
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								State.ts
									
										
									
									
									
								
							|  | @ -18,6 +18,7 @@ import Constants from "./Models/Constants"; | |||
| import UpdateFromOverpass from "./Logic/Actors/UpdateFromOverpass"; | ||||
| import LayerConfig from "./Customizations/JSON/LayerConfig"; | ||||
| import TitleHandler from "./Logic/Actors/TitleHandler"; | ||||
| import PendingChangesUploader from "./Logic/Actors/PendingChangesUploader"; | ||||
| 
 | ||||
| /** | ||||
|  * Contains the global state: a bunch of UI-event sources | ||||
|  | @ -207,6 +208,8 @@ export default class State { | |||
| 
 | ||||
|         this.allElements = new ElementStorage(); | ||||
|         this.changes = new Changes(); | ||||
|          | ||||
|         new PendingChangesUploader(this.changes, this.selectedElement); | ||||
| 
 | ||||
|         this.mangroveIdentity = new MangroveIdentity( | ||||
|             this.osmConnection.GetLongPreference("identity", "mangrove") | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue