| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  | import { Store, UIEventSource } from "../UIEventSource" | 
					
						
							|  |  |  | import { OsmConnection } from "./OsmConnection" | 
					
						
							| 
									
										
										
										
											2023-10-06 03:34:26 +02:00
										 |  |  | import { LocalStorageSource } from "../Web/LocalStorageSource" | 
					
						
							| 
									
										
										
										
											2024-08-23 02:16:24 +02:00
										 |  |  | import OSMAuthInstance = OSMAuth.osmAuth | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  | import { Utils } from "../../Utils" | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | export class OsmPreferences { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |     private preferences: Record<string, UIEventSource<string>> = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     private localStorageInited: Set<string> = new Set() | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Contains all the keys as returned by the OSM-preferences. | 
					
						
							|  |  |  |      * Used to clean up old preferences | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private seenKeys: string[] = [] | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private readonly _allPreferences: UIEventSource<Record<string, string>> = new UIEventSource({}) | 
					
						
							|  |  |  |     public readonly allPreferences: Store<Readonly<Record<string, string>>> = this._allPreferences | 
					
						
							| 
									
										
										
										
											2024-03-11 00:01:44 +01:00
										 |  |  |     private readonly _fakeUser: boolean | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     private readonly auth: OSMAuthInstance | 
					
						
							|  |  |  |     private readonly osmConnection: OsmConnection | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 00:01:44 +01:00
										 |  |  |     constructor(auth: OSMAuthInstance, osmConnection: OsmConnection, fakeUser: boolean = false) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         this.auth = auth | 
					
						
							| 
									
										
										
										
											2024-03-11 00:01:44 +01:00
										 |  |  |         this._fakeUser = fakeUser | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         this.osmConnection = osmConnection | 
					
						
							| 
									
										
										
										
											2023-11-23 17:06:30 +01:00
										 |  |  |         osmConnection.OnLoggedIn(() => { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |             this.loadBulkPreferences() | 
					
						
							| 
									
										
										
										
											2023-11-23 17:06:30 +01:00
										 |  |  |             return true | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 14:36:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     private setPreferencesAll(key: string, value: string) { | 
					
						
							|  |  |  |         if (this._allPreferences.data[key] !== value) { | 
					
						
							|  |  |  |             this._allPreferences.data[key] = value | 
					
						
							|  |  |  |             this._allPreferences.ping() | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-02-04 14:36:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-18 15:16:58 +02:00
										 |  |  |     private initPreference(key: string, value: string = undefined): UIEventSource<string> { | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         if (this.preferences[key] !== undefined) { | 
					
						
							| 
									
										
										
										
											2024-09-18 15:16:58 +02:00
										 |  |  |             if(value !== undefined){ | 
					
						
							|  |  |  |                 this.preferences[key].set(value) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |             return this.preferences[key] | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         const pref = this.preferences[key] = new UIEventSource(value, "preference: " + key) | 
					
						
							|  |  |  |         if (value) { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |             this.setPreferencesAll(key, value) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         pref.addCallback(v => { | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |             this.uploadKvSplit(key, v) | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |             this.setPreferencesAll(key, v) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         return pref | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     private async loadBulkPreferences() { | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         const prefs = await this.getPreferencesDictDirectly() | 
					
						
							|  |  |  |         this.seenKeys = Object.keys(prefs) | 
					
						
							|  |  |  |         const legacy = OsmPreferences.getLegacyCombinedItems(prefs) | 
					
						
							|  |  |  |         const merged = OsmPreferences.mergeDict(prefs) | 
					
						
							|  |  |  |         for (const key in merged) { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |             this.initPreference(key, prefs[key]) | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         for (const key in legacy) { | 
					
						
							|  |  |  |             this.initPreference(key, legacy[key]) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-12 16:14:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |     public getPreference( | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         key: string, | 
					
						
							|  |  |  |         defaultValue: string = undefined, | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         prefix?: string, | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         return this.getPreferenceSeedFromlocal(key, defaultValue, { prefix }) | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Gets a OSM-preference. | 
					
						
							|  |  |  |      * The OSM-preference is cached in local storage and updated from the OSM.org as soon as those values come in. | 
					
						
							|  |  |  |      * THis means that values written before being logged in might be erased by the cloud settings | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private getPreferenceSeedFromlocal( | 
					
						
							|  |  |  |         key: string, | 
					
						
							|  |  |  |         defaultValue: string = undefined, | 
					
						
							|  |  |  |         options?: { | 
					
						
							|  |  |  |             prefix?: string, | 
					
						
							|  |  |  |             saveToLocalStorage?: true | boolean | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     ): UIEventSource<string> { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         if (options?.prefix) { | 
					
						
							|  |  |  |             key = options.prefix + key | 
					
						
							| 
									
										
										
										
											2022-06-21 18:22:09 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-08-23 02:16:24 +02:00
										 |  |  |         key = key.replace(/[:/"' {}.%\\]/g, "") | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const localStorage = LocalStorageSource.Get(key) | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         if (localStorage.data === "null" || localStorage.data === "undefined") { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |             localStorage.set(undefined) | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-09-18 15:16:58 +02:00
										 |  |  |         const pref: UIEventSource<string> = this.initPreference(key, localStorage.data ?? defaultValue) | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         if (this.localStorageInited.has(key)) { | 
					
						
							|  |  |  |             return pref | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-01-11 03:53:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         if (options?.saveToLocalStorage ?? true) { | 
					
						
							|  |  |  |             pref.addCallback(v => localStorage.set(v)) // Keep a local copy
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this.localStorageInited.add(key) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return pref | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |     public ClearPreferences() { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         console.log("Starting to remove all preferences") | 
					
						
							|  |  |  |         this.removeAllWithPrefix("") | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * OsmPreferences.mergeDict({abc: "123", def: "123", "def:0": "456", "def:1":"789"}) // => {abc: "123", def: "123456789"}
 | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private static mergeDict(dict: Record<string, string>): Record<string, string> { | 
					
						
							|  |  |  |         const newDict = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const allKeys: string[] = Object.keys(dict) | 
					
						
							|  |  |  |         const normalKeys = allKeys.filter(k => !k.match(/[a-z-_0-9A-Z]*:[0-9]+/)) | 
					
						
							|  |  |  |         for (const normalKey of normalKeys) { | 
					
						
							|  |  |  |             if(normalKey.match(/-combined-[0-9]*$/) || normalKey.match(/-combined-length$/)){ | 
					
						
							|  |  |  |                 // Ignore legacy keys
 | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const partKeys = OsmPreferences.keysStartingWith(allKeys, normalKey) | 
					
						
							|  |  |  |             const parts = partKeys.map(k => dict[k]) | 
					
						
							|  |  |  |             newDict[normalKey] = parts.join("") | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return newDict | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Gets all items which have a 'combined'-string, the legacy long preferences | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      *   const input = { | 
					
						
							|  |  |  |      *             "extra-noncombined-key":"xyz", | 
					
						
							|  |  |  |      *             "mapcomplete-unofficial-theme-httpsrawgithubusercontentcomosm-catalanwikidataimgmainwikidataimgjson-combined-0": | 
					
						
							|  |  |  |      *                 "{\"id\":\"https://raw.githubusercontent.com/osm-catalan/wikidataimg/main/wikidataimg.json\",\"icon\":\"https://upload.wikimedia.org/wikipedia/commons/5/50/Yes_Check_Circle.svg\",\"title\":{\"ca\":\"wikidataimg\",\"_context\":\"themes:wikidataimg.title\"},\"shortDescription\"", | 
					
						
							|  |  |  |      *             "mapcomplete-unofficial-theme-httpsrawgithubusercontentcomosm-catalanwikidataimgmainwikidataimgjson-combined-1": | 
					
						
							|  |  |  |      *                 ":{\"ca\":\"Afegeix imatges d'articles de wikimedia\",\"_context\":\"themes:wikidataimg\"}}", | 
					
						
							|  |  |  |      *         } | 
					
						
							|  |  |  |      *         const merged = OsmPreferences.getLegacyCombinedItems(input) | 
					
						
							|  |  |  |      *         const data = merged["mapcomplete-unofficial-theme-httpsrawgithubusercontentcomosm-catalanwikidataimgmainwikidataimgjson"] | 
					
						
							|  |  |  |      *         JSON.parse(data) // =>  {"id": "https://raw.githubusercontent.com/osm-catalan/wikidataimg/main/wikidataimg.json", "icon": "https://upload.wikimedia.org/wikipedia/commons/5/50/Yes_Check_Circle.svg","title": { "ca": "wikidataimg", "_context": "themes:wikidataimg.title" }, "shortDescription": {"ca": "Afegeix imatges d'articles de wikimedia","_context": "themes:wikidataimg"}}
 | 
					
						
							|  |  |  |      *         merged["extra-noncombined-key"] // => undefined
 | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static getLegacyCombinedItems(dict: Record<string, string>): Record<string, string> { | 
					
						
							|  |  |  |         const merged: Record<string, string> = {} | 
					
						
							|  |  |  |         const keys = Object.keys(dict) | 
					
						
							|  |  |  |         const toCheck =Utils.NoNullInplace( Utils.Dedup(keys.map(k => k.match(/(.*)-combined-[0-9]+$/)?.[1]))) | 
					
						
							|  |  |  |         for (const key of toCheck) { | 
					
						
							|  |  |  |             let i = 0 | 
					
						
							|  |  |  |             let str = "" | 
					
						
							|  |  |  |             let v: string | 
					
						
							|  |  |  |             do { | 
					
						
							|  |  |  |                 v = dict[key + "-combined-" + i] | 
					
						
							|  |  |  |                 str += v ?? "" | 
					
						
							|  |  |  |                 i++ | 
					
						
							|  |  |  |             } while (v !== undefined) | 
					
						
							|  |  |  |             merged[key] = str | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return merged | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-11 00:01:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Bulk-downloads all preferences | 
					
						
							|  |  |  |      * @private | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |     private getPreferencesDictDirectly(): Promise<Record<string, string>> { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         return new Promise<Record<string, string>>((resolve, reject) => { | 
					
						
							|  |  |  |             this.auth.xhr( | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     method: "GET", | 
					
						
							|  |  |  |                     path: "/api/0.6/user/preferences", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 (error, value: XMLDocument) => { | 
					
						
							|  |  |  |                     if (error) { | 
					
						
							|  |  |  |                         console.log("Could not load preferences", error) | 
					
						
							|  |  |  |                         reject(error) | 
					
						
							|  |  |  |                         return | 
					
						
							| 
									
										
										
										
											2023-11-23 17:06:30 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |                     const prefs = value.getElementsByTagName("preference") | 
					
						
							|  |  |  |                     const dict: Record<string, string> = {} | 
					
						
							|  |  |  |                     for (let i = 0; i < prefs.length; i++) { | 
					
						
							|  |  |  |                         const pref = prefs[i] | 
					
						
							|  |  |  |                         const k = pref.getAttribute("k") | 
					
						
							|  |  |  |                         dict[k] = pref.getAttribute("v") | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |                     resolve(dict) | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |      * Returns all keys matching `k:[number]` | 
					
						
							|  |  |  |      * Split separately for test | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * const keys = ["abc", "def", "ghi", "ghi:0", "ghi:1"] | 
					
						
							|  |  |  |      * OsmPreferences.keysStartingWith(keys, "xyz") // => []
 | 
					
						
							|  |  |  |      * OsmPreferences.keysStartingWith(keys, "abc") // => ["abc"]
 | 
					
						
							|  |  |  |      * OsmPreferences.keysStartingWith(keys, "ghi") // => ["ghi", "ghi:0", "ghi:1"]
 | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private static keysStartingWith(allKeys: string[], key: string): string[] { | 
					
						
							|  |  |  |         const keys = allKeys.filter(k =>  k === key || k.match(new RegExp(key + ":[0-9]+"))) | 
					
						
							|  |  |  |         keys.sort() | 
					
						
							|  |  |  |         return keys | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Smart 'upload', which splits the value into `k`, `k:0`, `k:1` if needed. | 
					
						
							|  |  |  |      * If `v` is null, undefined, empty, "undefined" (literal string) or "null" (literal string), will delete `k` and `k:[number]` | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private async uploadKvSplit(k: string, v: string) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (v === null || v === undefined || v === "" || v === "undefined" || v === "null") { | 
					
						
							|  |  |  |             const keysToDelete = OsmPreferences.keysStartingWith(this.seenKeys, k) | 
					
						
							|  |  |  |             await Promise.all(keysToDelete.map(k => this.deleteKeyDirectly(k))) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await this.uploadKeyDirectly(k, v.slice(0, 255)) | 
					
						
							|  |  |  |         v = v.slice(255) | 
					
						
							|  |  |  |         let i = 0 | 
					
						
							|  |  |  |         while (v.length > 0) { | 
					
						
							|  |  |  |             await this.uploadKeyDirectly(`${k}:${i}`, v.slice(0, 255)) | 
					
						
							|  |  |  |             v = v.slice(255) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Directly deletes this key | 
					
						
							|  |  |  |      * @param k | 
					
						
							|  |  |  |      * @private | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private deleteKeyDirectly(k: string) { | 
					
						
							|  |  |  |         if (!this.osmConnection.userDetails.data.loggedIn) { | 
					
						
							|  |  |  |             console.debug(`Not saving preference ${k}: user not logged in`) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (this._fakeUser) { | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return new Promise<void>((resolve, reject) => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 this.auth.xhr( | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         method: "DELETE", | 
					
						
							|  |  |  |                         path: "/api/0.6/user/preferences/" + encodeURIComponent(k), | 
					
						
							|  |  |  |                         headers: { "Content-Type": "text/plain" }, | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     (error) => { | 
					
						
							|  |  |  |                         if (error) { | 
					
						
							|  |  |  |                             console.warn("Could not remove preference", error) | 
					
						
							|  |  |  |                             reject(error) | 
					
						
							|  |  |  |                             return | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         console.debug("Preference ", k, "removed!") | 
					
						
							|  |  |  |                         resolve() | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Uploads the given k=v to the OSM-server | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |      * Deletes it if 'v' is undefined, null or empty | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |     private async uploadKeyDirectly(k: string, v: string) { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         if (!this.osmConnection.userDetails.data.loggedIn) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             console.debug(`Not saving preference ${k}: user not logged in`) | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 00:01:44 +01:00
										 |  |  |         if (this._fakeUser) { | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         if (v === undefined || v === "" || v === null) { | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |             await this.deleteKeyDirectly(k) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (v.length > 255) { | 
					
						
							|  |  |  |             console.error("Preference too long, max 255 chars", { k, v }) | 
					
						
							|  |  |  |             throw "Preference too long, at most 255 characters are supported" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return new Promise<void>((resolve, reject) => { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             this.auth.xhr( | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |                     method: "PUT", | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     path: "/api/0.6/user/preferences/" + encodeURIComponent(k), | 
					
						
							| 
									
										
										
										
											2024-03-11 00:01:44 +01:00
										 |  |  |                     headers: { "Content-Type": "text/plain" }, | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |                     content: v, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2024-08-23 02:16:24 +02:00
										 |  |  |                 (error) => { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     if (error) { | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |                         console.warn(`Could not set preference "${k}"'`, error) | 
					
						
							|  |  |  |                         reject(error) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         return | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |                     resolve() | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2020-08-26 15:36:04 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |     async removeAllWithPrefix(prefix: string) { | 
					
						
							|  |  |  |         const keys = this.seenKeys | 
					
						
							|  |  |  |         for (const key in keys) { | 
					
						
							|  |  |  |             await this.deleteKeyDirectly(key) | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |     getExistingPreference(key: string, defaultValue: undefined, prefix: string): UIEventSource<string> { | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  |         if (prefix) { | 
					
						
							|  |  |  |             key = prefix + key | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         key = key.replace(/[:/"' {}.%\\]/g, "") | 
					
						
							| 
									
										
										
										
											2024-09-16 23:36:42 +02:00
										 |  |  |         return this.preferences[key] | 
					
						
							| 
									
										
										
										
											2024-09-10 02:19:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | } |