forked from MapComplete/MapComplete
chore: automated housekeeping...
This commit is contained in:
parent
c9ce29f206
commit
40e894df8b
294 changed files with 14209 additions and 4192 deletions
|
|
@ -33,7 +33,7 @@ export default class ChangeLocationAction extends OsmChangeAction {
|
|||
meta: {
|
||||
theme: string
|
||||
reason: string
|
||||
},
|
||||
}
|
||||
) {
|
||||
super(id, true)
|
||||
this.state = state
|
||||
|
|
@ -66,12 +66,10 @@ export default class ChangeLocationAction extends OsmChangeAction {
|
|||
return [d]
|
||||
}
|
||||
|
||||
const insertIntoWay = new InsertPointIntoWayAction(
|
||||
lat, lon, this._id, snapToWay, {
|
||||
allowReuseOfPreviouslyCreatedPoints: false,
|
||||
reusePointWithinMeters: 0.25,
|
||||
},
|
||||
).prepareChangeDescription()
|
||||
const insertIntoWay = new InsertPointIntoWayAction(lat, lon, this._id, snapToWay, {
|
||||
allowReuseOfPreviouslyCreatedPoints: false,
|
||||
reusePointWithinMeters: 0.25,
|
||||
}).prepareChangeDescription()
|
||||
|
||||
return [d, { ...insertIntoWay, meta: d.meta }]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
|
|||
theme: string
|
||||
changeType: "create" | "import" | null
|
||||
specialMotivation?: string
|
||||
},
|
||||
}
|
||||
) {
|
||||
super(null, basicTags !== undefined && basicTags.length > 0)
|
||||
this._basicTags = basicTags
|
||||
|
|
@ -102,21 +102,12 @@ export default class CreateNewNodeAction extends OsmCreateAction {
|
|||
return [newPointChange]
|
||||
}
|
||||
|
||||
const change = new InsertPointIntoWayAction(
|
||||
this._lat,
|
||||
this._lon,
|
||||
id,
|
||||
this._snapOnto,
|
||||
{
|
||||
reusePointWithinMeters: this._reusePointDistance,
|
||||
allowReuseOfPreviouslyCreatedPoints: this._reusePreviouslyCreatedPoint,
|
||||
},
|
||||
).prepareChangeDescription()
|
||||
const change = new InsertPointIntoWayAction(this._lat, this._lon, id, this._snapOnto, {
|
||||
reusePointWithinMeters: this._reusePointDistance,
|
||||
allowReuseOfPreviouslyCreatedPoints: this._reusePreviouslyCreatedPoint,
|
||||
}).prepareChangeDescription()
|
||||
|
||||
return [
|
||||
newPointChange,
|
||||
{ ...change, meta: this.meta },
|
||||
]
|
||||
return [newPointChange, { ...change, meta: this.meta }]
|
||||
}
|
||||
|
||||
private setElementId(id: number) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { ChangeDescription } from "./ChangeDescription"
|
|||
import { GeoOperations } from "../../GeoOperations"
|
||||
import { OsmWay } from "../OsmObject"
|
||||
|
||||
export default class InsertPointIntoWayAction {
|
||||
export default class InsertPointIntoWayAction {
|
||||
private readonly _lat: number
|
||||
private readonly _lon: number
|
||||
private readonly _idToInsert: number
|
||||
|
|
@ -21,22 +21,19 @@ export default class InsertPointIntoWayAction {
|
|||
allowReuseOfPreviouslyCreatedPoints?: boolean
|
||||
reusePointWithinMeters?: number
|
||||
}
|
||||
){
|
||||
) {
|
||||
this._lat = lat
|
||||
this._lon = lon
|
||||
this._idToInsert = idToInsert
|
||||
this._snapOnto = snapOnto
|
||||
this._options = options
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to create the changedescription of the way where the point is inserted
|
||||
* Returns `undefined` if inserting failed
|
||||
*/
|
||||
public prepareChangeDescription(): Omit<ChangeDescription, "meta"> | undefined {
|
||||
|
||||
|
||||
public prepareChangeDescription(): Omit<ChangeDescription, "meta"> | undefined {
|
||||
// Project the point onto the way
|
||||
console.log("Snapping a node onto an existing way...")
|
||||
const geojson = this._snapOnto.asGeoJson()
|
||||
|
|
@ -59,13 +56,19 @@ export default class InsertPointIntoWayAction {
|
|||
}
|
||||
|
||||
const prev = outerring[index]
|
||||
if (GeoOperations.distanceBetween(prev, projectedCoor) < this._options.reusePointWithinMeters) {
|
||||
if (
|
||||
GeoOperations.distanceBetween(prev, projectedCoor) <
|
||||
this._options.reusePointWithinMeters
|
||||
) {
|
||||
// We reuse this point instead!
|
||||
reusedPointId = this._snapOnto.nodes[index]
|
||||
reusedPointCoordinates = this._snapOnto.coordinates[index]
|
||||
}
|
||||
const next = outerring[index + 1]
|
||||
if (GeoOperations.distanceBetween(next, projectedCoor) < this._options.reusePointWithinMeters) {
|
||||
if (
|
||||
GeoOperations.distanceBetween(next, projectedCoor) <
|
||||
this._options.reusePointWithinMeters
|
||||
) {
|
||||
// We reuse this point instead!
|
||||
reusedPointId = this._snapOnto.nodes[index + 1]
|
||||
reusedPointCoordinates = this._snapOnto.coordinates[index + 1]
|
||||
|
|
@ -82,15 +85,13 @@ export default class InsertPointIntoWayAction {
|
|||
locations.splice(index + 1, 0, [this._lon, this._lat])
|
||||
ids.splice(index + 1, 0, this._idToInsert)
|
||||
|
||||
return {
|
||||
return {
|
||||
type: "way",
|
||||
id: this._snapOnto.id,
|
||||
changes: {
|
||||
coordinates: locations,
|
||||
nodes: ids,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
const url = `${
|
||||
this.state.osmConnection?._oauth_config?.url ?? "https://api.openstreetmap.org"
|
||||
}/api/0.6/${this.wayToReplaceId}/full`
|
||||
const rawData = await Utils.downloadJsonCached<{elements: any[]}>(url, 1000)
|
||||
const rawData = await Utils.downloadJsonCached<{ elements: any[] }>(url, 1000)
|
||||
parsed = OsmObject.ParseObjects(rawData.elements)
|
||||
}
|
||||
const allNodes = parsed.filter((o) => o.type === "node")
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ export class Changes {
|
|||
featureSwitches: {
|
||||
featureSwitchMorePrivacy?: Store<boolean>
|
||||
featureSwitchIsTesting?: Store<boolean>
|
||||
},
|
||||
osmConnection: OsmConnection,
|
||||
reportError?: (error: string) => void,
|
||||
featureProperties?: FeaturePropertiesStore,
|
||||
historicalUserLocations?: FeatureSource,
|
||||
}
|
||||
osmConnection: OsmConnection
|
||||
reportError?: (error: string) => void
|
||||
featureProperties?: FeaturePropertiesStore
|
||||
historicalUserLocations?: FeatureSource
|
||||
allElements?: IndexedFeatureSource
|
||||
},
|
||||
leftRightSensitive: boolean = false,
|
||||
|
|
@ -64,8 +64,11 @@ export class Changes {
|
|||
this.allChanges.setData([...this.pendingChanges.data])
|
||||
// If a pending change contains a negative ID, we save that
|
||||
this._nextId = Math.min(-1, ...(this.pendingChanges.data?.map((pch) => pch.id ?? 0) ?? []))
|
||||
if(isNaN(this._nextId) && state.reportError !== undefined){
|
||||
state.reportError("Got a NaN as nextID. Pending changes IDs are:" +this.pendingChanges.data?.map(pch => pch?.id).join("."))
|
||||
if (isNaN(this._nextId) && state.reportError !== undefined) {
|
||||
state.reportError(
|
||||
"Got a NaN as nextID. Pending changes IDs are:" +
|
||||
this.pendingChanges.data?.map((pch) => pch?.id).join(".")
|
||||
)
|
||||
this._nextId = -100
|
||||
}
|
||||
this.state = state
|
||||
|
|
@ -84,12 +87,12 @@ export class Changes {
|
|||
// This doesn't matter however, as the '-1' is per piecewise upload, not global per changeset
|
||||
}
|
||||
|
||||
public static createTestObject(): Changes{
|
||||
public static createTestObject(): Changes {
|
||||
return new Changes({
|
||||
osmConnection: new OsmConnection(),
|
||||
featureSwitches:{
|
||||
featureSwitchIsTesting: new ImmutableStore(true)
|
||||
}
|
||||
featureSwitches: {
|
||||
featureSwitchIsTesting: new ImmutableStore(true),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -837,12 +840,16 @@ export class Changes {
|
|||
)
|
||||
|
||||
// We keep all the refused changes to try them again
|
||||
this.pendingChanges.setData(refusedChanges.flatMap((c) => c).filter(c => {
|
||||
if(c.id === null || c.id === undefined){
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}))
|
||||
this.pendingChanges.setData(
|
||||
refusedChanges
|
||||
.flatMap((c) => c)
|
||||
.filter((c) => {
|
||||
if (c.id === null || c.id === undefined) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
)
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"Could not handle changes - probably an old, pending changeset in localstorage with an invalid format; erasing those",
|
||||
|
|
|
|||
|
|
@ -205,12 +205,12 @@ export class ChangesetHandler {
|
|||
try {
|
||||
return await this.UploadWithNew(generateChangeXML, openChangeset, extraMetaTags)
|
||||
} catch (e) {
|
||||
const req = (<XMLHttpRequest>e)
|
||||
const req = <XMLHttpRequest>e
|
||||
if (req.status === 403) {
|
||||
// Someone got the banhammer
|
||||
// This is the message that OSM returned, will be something like "you have an important message, go to osm.org"
|
||||
const msg = req.responseText
|
||||
alert(msg+"\n\nWe'll take you to openstreetmap.org now")
|
||||
const msg = req.responseText
|
||||
alert(msg + "\n\nWe'll take you to openstreetmap.org now")
|
||||
window.location.replace(this.osmConnection.Backend())
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,14 +45,14 @@ export class OsmConnection {
|
|||
public userDetails: UIEventSource<UserDetails>
|
||||
public isLoggedIn: Store<boolean>
|
||||
public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
||||
"unknown",
|
||||
"unknown"
|
||||
)
|
||||
public apiIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
||||
"unknown",
|
||||
"unknown"
|
||||
)
|
||||
|
||||
public loadingStatus = new UIEventSource<"not-attempted" | "loading" | "error" | "logged-in">(
|
||||
"not-attempted",
|
||||
"not-attempted"
|
||||
)
|
||||
public preferencesHandler: OsmPreferences
|
||||
public readonly _oauth_config: AuthConfig
|
||||
|
|
@ -96,7 +96,7 @@ export class OsmConnection {
|
|||
|
||||
this.userDetails = new UIEventSource<UserDetails>(
|
||||
new UserDetails(this._oauth_config.url),
|
||||
"userDetails",
|
||||
"userDetails"
|
||||
)
|
||||
if (options.fakeUser) {
|
||||
const ud = this.userDetails.data
|
||||
|
|
@ -117,7 +117,7 @@ export class OsmConnection {
|
|||
(user) =>
|
||||
user.loggedIn &&
|
||||
(this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"),
|
||||
[this.apiIsOnline],
|
||||
[this.apiIsOnline]
|
||||
)
|
||||
this.isLoggedIn.addCallback((isLoggedIn) => {
|
||||
if (this.userDetails.data.loggedIn == false && isLoggedIn == true) {
|
||||
|
|
@ -160,17 +160,16 @@ export class OsmConnection {
|
|||
defaultValue: string = undefined,
|
||||
options?: {
|
||||
prefix?: string
|
||||
},
|
||||
}
|
||||
): UIEventSource<T | undefined> {
|
||||
const prefix = options?.prefix ?? "mapcomplete-"
|
||||
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
|
||||
|
||||
}
|
||||
|
||||
public getPreference<T extends string = string>(
|
||||
key: string,
|
||||
defaultValue: string = undefined,
|
||||
prefix: string = "mapcomplete-",
|
||||
prefix: string = "mapcomplete-"
|
||||
): UIEventSource<T | undefined> {
|
||||
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
|
||||
}
|
||||
|
|
@ -214,7 +213,7 @@ export class OsmConnection {
|
|||
this.updateAuthObject()
|
||||
|
||||
LocalStorageSource.get("location_before_login").setData(
|
||||
Utils.runningFromConsole ? undefined : window.location.href,
|
||||
Utils.runningFromConsole ? undefined : window.location.href
|
||||
)
|
||||
this.auth.xhr(
|
||||
{
|
||||
|
|
@ -252,13 +251,13 @@ export class OsmConnection {
|
|||
data.account_created = userInfo.getAttribute("account_created")
|
||||
data.uid = Number(userInfo.getAttribute("id"))
|
||||
data.languages = Array.from(
|
||||
userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang"),
|
||||
userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang")
|
||||
).map((l) => l.textContent)
|
||||
data.csCount = Number.parseInt(
|
||||
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0",
|
||||
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0"
|
||||
)
|
||||
data.tracesCount = Number.parseInt(
|
||||
userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0",
|
||||
userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0"
|
||||
)
|
||||
|
||||
data.img = undefined
|
||||
|
|
@ -290,7 +289,7 @@ export class OsmConnection {
|
|||
action(this.userDetails.data)
|
||||
}
|
||||
this._onLoggedIn = []
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -308,7 +307,7 @@ export class OsmConnection {
|
|||
method: "GET" | "POST" | "PUT" | "DELETE",
|
||||
header?: Record<string, string>,
|
||||
content?: string,
|
||||
allowAnonymous: boolean = false,
|
||||
allowAnonymous: boolean = false
|
||||
): Promise<string> {
|
||||
const connection: osmAuth = this.auth
|
||||
if (allowAnonymous && !this.auth.authenticated()) {
|
||||
|
|
@ -316,7 +315,7 @@ export class OsmConnection {
|
|||
`${this.Backend()}/api/0.6/${path}`,
|
||||
header,
|
||||
method,
|
||||
content,
|
||||
content
|
||||
)
|
||||
if (possibleResult["content"]) {
|
||||
return possibleResult["content"]
|
||||
|
|
@ -333,13 +332,13 @@ export class OsmConnection {
|
|||
content,
|
||||
path: `/api/0.6/${path}`,
|
||||
},
|
||||
function(err, response) {
|
||||
function (err, response) {
|
||||
if (err !== null) {
|
||||
error(err)
|
||||
} else {
|
||||
ok(response)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -348,7 +347,7 @@ export class OsmConnection {
|
|||
path: string,
|
||||
content?: string,
|
||||
header?: Record<string, string>,
|
||||
allowAnonymous: boolean = false,
|
||||
allowAnonymous: boolean = false
|
||||
): Promise<T> {
|
||||
return <T>await this.interact(path, "POST", header, content, allowAnonymous)
|
||||
}
|
||||
|
|
@ -356,7 +355,7 @@ export class OsmConnection {
|
|||
public async put<T extends string>(
|
||||
path: string,
|
||||
content?: string,
|
||||
header?: Record<string, string>,
|
||||
header?: Record<string, string>
|
||||
): Promise<T> {
|
||||
return <T>await this.interact(path, "PUT", header, content)
|
||||
}
|
||||
|
|
@ -364,7 +363,7 @@ export class OsmConnection {
|
|||
public async get(
|
||||
path: string,
|
||||
header?: Record<string, string>,
|
||||
allowAnonymous: boolean = false,
|
||||
allowAnonymous: boolean = false
|
||||
): Promise<string> {
|
||||
return await this.interact(path, "GET", header, undefined, allowAnonymous)
|
||||
}
|
||||
|
|
@ -403,7 +402,7 @@ export class OsmConnection {
|
|||
return new Promise<{ id: number }>((ok) => {
|
||||
window.setTimeout(
|
||||
() => ok({ id: Math.floor(Math.random() * 1000) }),
|
||||
Math.random() * 5000,
|
||||
Math.random() * 5000
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -415,7 +414,7 @@ export class OsmConnection {
|
|||
{
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
},
|
||||
true,
|
||||
true
|
||||
)
|
||||
const parsed = JSON.parse(response)
|
||||
console.log("Got result:", parsed)
|
||||
|
|
@ -438,14 +437,14 @@ export class OsmConnection {
|
|||
* Note: these are called 'tags' on the wiki, but I opted to name them 'labels' instead as they aren't "key=value" tags, but just words.
|
||||
*/
|
||||
labels: string[]
|
||||
},
|
||||
}
|
||||
): Promise<{ id: number }> {
|
||||
if (this._dryRun.data) {
|
||||
console.warn("Dryrun enabled - not actually uploading GPX ", gpx)
|
||||
return new Promise<{ id: number }>((ok) => {
|
||||
window.setTimeout(
|
||||
() => ok({ id: Math.floor(Math.random() * 1000) }),
|
||||
Math.random() * 5000,
|
||||
Math.random() * 5000
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -462,9 +461,9 @@ export class OsmConnection {
|
|||
}
|
||||
const extras = {
|
||||
file:
|
||||
"; filename=\"" +
|
||||
'; filename="' +
|
||||
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
|
||||
"\"\r\nContent-Type: application/gpx+xml",
|
||||
'"\r\nContent-Type: application/gpx+xml',
|
||||
}
|
||||
|
||||
const boundary = "987654"
|
||||
|
|
@ -472,7 +471,7 @@ export class OsmConnection {
|
|||
let body = ""
|
||||
for (const key in contents) {
|
||||
body += "--" + boundary + "\r\n"
|
||||
body += "Content-Disposition: form-data; name=\"" + key + "\""
|
||||
body += 'Content-Disposition: form-data; name="' + key + '"'
|
||||
if (extras[key] !== undefined) {
|
||||
body += extras[key]
|
||||
}
|
||||
|
|
@ -506,13 +505,13 @@ export class OsmConnection {
|
|||
|
||||
path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`,
|
||||
},
|
||||
function(err) {
|
||||
function (err) {
|
||||
if (err !== null) {
|
||||
error(err)
|
||||
} else {
|
||||
ok()
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -521,7 +520,7 @@ export class OsmConnection {
|
|||
* To be called by land.html
|
||||
*/
|
||||
public finishLogin(callback: (previousURL: string) => void) {
|
||||
this.auth.authenticate(function() {
|
||||
this.auth.authenticate(function () {
|
||||
// Fully authed at this point
|
||||
console.log("Authentication successful!")
|
||||
const previousLocation = LocalStorageSource.get("location_before_login")
|
||||
|
|
@ -538,8 +537,8 @@ export class OsmConnection {
|
|||
? "https://mapcomplete.org/land.html"
|
||||
: window.location.protocol + "//" + window.location.host + "/land.html",
|
||||
/* We use 'singlePage' as much as possible, it is the most stable - including in PWA.
|
||||
* However, this breaks in iframes so we open a popup in that case
|
||||
*/
|
||||
* However, this breaks in iframes so we open a popup in that case
|
||||
*/
|
||||
singlepage: !this._iframeMode,
|
||||
auto: true,
|
||||
apiUrl: this._oauth_config.api_url ?? this._oauth_config.url,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import OSMAuthInstance = OSMAuth.osmAuth
|
|||
import { Utils } from "../../Utils"
|
||||
|
||||
export class OsmPreferences {
|
||||
|
||||
/**
|
||||
* A 'cache' of all the preference stores
|
||||
* @private
|
||||
|
|
@ -39,7 +38,6 @@ export class OsmPreferences {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
private setPreferencesAll(key: string, value: string) {
|
||||
if (this._allPreferences.data[key] !== value) {
|
||||
this._allPreferences.data[key] = value
|
||||
|
|
@ -54,11 +52,11 @@ export class OsmPreferences {
|
|||
}
|
||||
return this.preferences[key]
|
||||
}
|
||||
const pref = this.preferences[key] = new UIEventSource(value, "preference: " + key)
|
||||
const pref = (this.preferences[key] = new UIEventSource(value, "preference: " + key))
|
||||
if (value) {
|
||||
this.setPreferencesAll(key, value)
|
||||
}
|
||||
pref.addCallback(v => {
|
||||
pref.addCallback((v) => {
|
||||
console.log("Got an update:", key, "--->", v)
|
||||
this.uploadKvSplit(key, v)
|
||||
this.setPreferencesAll(key, v)
|
||||
|
|
@ -71,7 +69,7 @@ export class OsmPreferences {
|
|||
this.seenKeys = Object.keys(prefs)
|
||||
const legacy = OsmPreferences.getLegacyCombinedItems(prefs)
|
||||
const merged = OsmPreferences.mergeDict(prefs)
|
||||
if(Object.keys(legacy).length > 0){
|
||||
if (Object.keys(legacy).length > 0) {
|
||||
await this.removeLegacy(legacy)
|
||||
}
|
||||
for (const key in merged) {
|
||||
|
|
@ -82,12 +80,7 @@ export class OsmPreferences {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public getPreference(
|
||||
key: string,
|
||||
defaultValue: string = undefined,
|
||||
prefix?: string,
|
||||
) {
|
||||
public getPreference(key: string, defaultValue: string = undefined, prefix?: string) {
|
||||
return this.getPreferenceSeedFromlocal(key, defaultValue, { prefix })
|
||||
}
|
||||
|
||||
|
|
@ -100,27 +93,29 @@ export class OsmPreferences {
|
|||
key: string,
|
||||
defaultValue: string = undefined,
|
||||
options?: {
|
||||
prefix?: string,
|
||||
prefix?: string
|
||||
saveToLocalStorage?: true | boolean
|
||||
},
|
||||
}
|
||||
): UIEventSource<string> {
|
||||
if (options?.prefix) {
|
||||
key = options.prefix + key
|
||||
}
|
||||
key = key.replace(/[:/"' {}.%\\]/g, "")
|
||||
|
||||
|
||||
const localStorage = LocalStorageSource.get(key) // cached
|
||||
if (localStorage.data === "null" || localStorage.data === "undefined") {
|
||||
localStorage.set(undefined)
|
||||
}
|
||||
const pref: UIEventSource<string> = this.initPreference(key, localStorage.data ?? defaultValue) // cached
|
||||
const pref: UIEventSource<string> = this.initPreference(
|
||||
key,
|
||||
localStorage.data ?? defaultValue
|
||||
) // cached
|
||||
if (this.localStorageInited.has(key)) {
|
||||
return pref
|
||||
}
|
||||
|
||||
if (options?.saveToLocalStorage ?? true) {
|
||||
pref.addCallback(v => localStorage.set(v)) // Keep a local copy
|
||||
pref.addCallback((v) => localStorage.set(v)) // Keep a local copy
|
||||
}
|
||||
this.localStorageInited.add(key)
|
||||
return pref
|
||||
|
|
@ -134,7 +129,7 @@ export class OsmPreferences {
|
|||
public async removeLegacy(legacyDict: Record<string, string>) {
|
||||
for (const k in legacyDict) {
|
||||
const v = legacyDict[k]
|
||||
console.log("Upgrading legacy preference",k )
|
||||
console.log("Upgrading legacy preference", k)
|
||||
await this.removeAllWithPrefix(k)
|
||||
this.osmConnection.getPreference(k).set(v)
|
||||
}
|
||||
|
|
@ -148,20 +143,19 @@ export class OsmPreferences {
|
|||
const newDict = {}
|
||||
|
||||
const allKeys: string[] = Object.keys(dict)
|
||||
const normalKeys = allKeys.filter(k => !k.match(/[a-z-_0-9A-Z]*:[0-9]+/))
|
||||
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])
|
||||
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
|
||||
*
|
||||
|
|
@ -180,7 +174,9 @@ export class OsmPreferences {
|
|||
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])))
|
||||
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 = ""
|
||||
|
|
@ -195,7 +191,6 @@ export class OsmPreferences {
|
|||
return merged
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bulk-downloads all preferences
|
||||
* @private
|
||||
|
|
@ -221,10 +216,9 @@ export class OsmPreferences {
|
|||
dict[k] = pref.getAttribute("v")
|
||||
}
|
||||
resolve(dict)
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -238,7 +232,7 @@ export class OsmPreferences {
|
|||
*
|
||||
*/
|
||||
private static keysStartingWith(allKeys: string[], key: string): string[] {
|
||||
const keys = allKeys.filter(k => k === key || k.match(new RegExp(key + ":[0-9]+")))
|
||||
const keys = allKeys.filter((k) => k === key || k.match(new RegExp(key + ":[0-9]+")))
|
||||
keys.sort()
|
||||
return keys
|
||||
}
|
||||
|
|
@ -249,14 +243,12 @@ export class OsmPreferences {
|
|||
*
|
||||
*/
|
||||
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)))
|
||||
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
|
||||
|
|
@ -265,7 +257,6 @@ export class OsmPreferences {
|
|||
v = v.slice(255)
|
||||
i++
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -283,25 +274,23 @@ export class OsmPreferences {
|
|||
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()
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
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()
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -328,7 +317,6 @@ export class OsmPreferences {
|
|||
}
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
|
||||
this.auth.xhr(
|
||||
{
|
||||
method: "PUT",
|
||||
|
|
@ -343,7 +331,7 @@ export class OsmPreferences {
|
|||
return
|
||||
}
|
||||
resolve()
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -351,12 +339,10 @@ export class OsmPreferences {
|
|||
async removeAllWithPrefix(prefix: string) {
|
||||
const keys = this.seenKeys
|
||||
for (const key of keys) {
|
||||
if(!key.startsWith(prefix)){
|
||||
if (!key.startsWith(prefix)) {
|
||||
continue
|
||||
}
|
||||
await this.deleteKeyDirectly(key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue