import {UIEventSource} from "../UIEventSource"; import UserDetails, {OsmConnection} from "./OsmConnection"; import {Utils} from "../../Utils"; export class OsmPreferences { public preferences = new UIEventSource({}, "all-osm-preferences"); public preferenceSources: any = {} private auth: any; private userDetails: UIEventSource; private longPreferences = {}; constructor(auth, osmConnection: OsmConnection) { this.auth = auth; this.userDetails = osmConnection.userDetails; const self = this; osmConnection.OnLoggedIn(() => self.UpdatePreferences()); } /** * OSM preferences can be at most 255 chars * @param key * @param prefix * @constructor */ public GetLongPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource { if (this.longPreferences[prefix + key] !== undefined) { return this.longPreferences[prefix + key]; } const source = new UIEventSource(undefined, "long-osm-preference:" + prefix + key); this.longPreferences[prefix + key] = source; const allStartWith = prefix + key + "-combined"; // Gives the number of combined preferences const length = this.GetPreference(allStartWith + "-length", ""); const self = this; source.addCallback(str => { if (str === undefined || str === "") { return; } if (str === null) { console.error("Deleting " + allStartWith); let count = parseInt(length.data); for (let i = 0; i < count; i++) { // Delete all the preferences self.GetPreference(allStartWith + "-" + i, "") .setData(""); } self.GetPreference(allStartWith + "-length", "") .setData(""); return } let i = 0; while (str !== "") { if (str === undefined || str === "undefined") { throw "Long pref became undefined?" } if (i > 100) { throw "This long preference is getting very long... " } self.GetPreference(allStartWith + "-" + i, "").setData(str.substr(0, 255)); str = str.substr(255); i++; } length.setData("" + i); // We use I, the number of preference fields used }); function updateData(l: number) { if (l === undefined) { source.setData(undefined); return; } const prefsCount = Number(l); if (prefsCount > 100) { throw "Length to long"; } let str = ""; for (let i = 0; i < prefsCount; i++) { str += self.GetPreference(allStartWith + "-" + i, "").data; } source.setData(str); } length.addCallback(l => { updateData(Number(l)); }); updateData(Number(length.data)); return source; } public GetPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource { key = prefix + key; key = key.replace(/[:\\\/"' {}.%]/g, '') if (key.length >= 255) { throw "Preferences: key length to big"; } if (this.preferenceSources[key] !== undefined) { return this.preferenceSources[key]; } if (this.userDetails.data.loggedIn && this.preferences.data[key] === undefined) { this.UpdatePreferences(); } const pref = new UIEventSource(this.preferences.data[key], "osm-preference:" + key); pref.addCallback((v) => { this.SetPreference(key, v); }); this.preferences.addCallback((prefs) => { if (prefs[key] !== undefined) { pref.setData(prefs[key]); } }); this.preferenceSources[key] = pref; return pref; } private UpdatePreferences() { const self = this; this.auth.xhr({ method: 'GET', path: '/api/0.6/user/preferences' }, function (error, value: XMLDocument) { if (error) { console.log("Could not load preferences", error); return; } const prefs = value.getElementsByTagName("preference"); for (let i = 0; i < prefs.length; i++) { const pref = prefs[i]; const k = pref.getAttribute("k"); const v = pref.getAttribute("v"); self.preferences.data[k] = v; } self.preferences.ping(); }); } private SetPreference(k: string, v: string) { if (!this.userDetails.data.loggedIn) { console.debug(`Not saving preference ${k}: user not logged in`); return; } if (this.preferences.data[k] === v) { return; } console.debug("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15)); if (v === undefined || v === "") { this.auth.xhr({ method: 'DELETE', path: '/api/0.6/user/preferences/' + encodeURIComponent(k), options: {header: {'Content-Type': 'text/plain'}}, }, function (error) { if (error) { console.warn("Could not remove preference", error); return; } console.debug("Preference ", k, "removed!"); }); return; } this.auth.xhr({ method: 'PUT', path: '/api/0.6/user/preferences/' + encodeURIComponent(k), options: {header: {'Content-Type': 'text/plain'}}, content: v }, function (error) { if (error) { console.log(`Could not set preference "${k}"'`, error); return; } console.log(`Preference ${k} written!`); }); } }