forked from MapComplete/MapComplete
		
	First version which caches changesets if not uploaded
This commit is contained in:
		
							parent
							
								
									d72dbc21df
								
							
						
					
					
						commit
						6732c12a0c
					
				
					 7 changed files with 84 additions and 41 deletions
				
			
		| 
						 | 
					@ -7,6 +7,7 @@ import FeatureSource from "../FeatureSource/FeatureSource";
 | 
				
			||||||
import {TagsFilter} from "../Tags/TagsFilter";
 | 
					import {TagsFilter} from "../Tags/TagsFilter";
 | 
				
			||||||
import {Tag} from "../Tags/Tag";
 | 
					import {Tag} from "../Tags/Tag";
 | 
				
			||||||
import {OsmConnection} from "./OsmConnection";
 | 
					import {OsmConnection} from "./OsmConnection";
 | 
				
			||||||
 | 
					import {LocalStorageSource} from "../Web/LocalStorageSource";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Handles all changes made to OSM.
 | 
					 * Handles all changes made to OSM.
 | 
				
			||||||
| 
						 | 
					@ -24,8 +25,13 @@ export class Changes implements FeatureSource {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * All the pending changes
 | 
					     * All the pending changes
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public readonly pending: UIEventSource<{ elementId: string, key: string, value: string }[]> =
 | 
					    public readonly pending: UIEventSource<{ elementId: string, key: string, value: string }[]> = LocalStorageSource.GetParsed("pending-changes", [])
 | 
				
			||||||
        new UIEventSource<{ elementId: string; key: string; value: string }[]>([]);
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * All the pending new objects to upload
 | 
				
			||||||
 | 
					     * @private
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private readonly newObjects: UIEventSource<{ id: number, lat: number, lon: number }[]> = LocalStorageSource.GetParsed("newObjects", [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a change to the pending changes
 | 
					     * Adds a change to the pending changes
 | 
				
			||||||
| 
						 | 
					@ -82,8 +88,7 @@ export class Changes implements FeatureSource {
 | 
				
			||||||
        if (flushreason !== undefined) {
 | 
					        if (flushreason !== undefined) {
 | 
				
			||||||
            console.log(flushreason)
 | 
					            console.log(flushreason)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.uploadAll([], this.pending.data);
 | 
					        this.uploadAll();
 | 
				
			||||||
        this.pending.setData([]);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -93,12 +98,12 @@ export class Changes implements FeatureSource {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public createElement(basicTags: Tag[], lat: number, lon: number) {
 | 
					    public createElement(basicTags: Tag[], lat: number, lon: number) {
 | 
				
			||||||
        console.log("Creating a new element with ", basicTags)
 | 
					        console.log("Creating a new element with ", basicTags)
 | 
				
			||||||
        const osmNode = new OsmNode(Changes._nextId);
 | 
					        const newId = Changes._nextId;
 | 
				
			||||||
        Changes._nextId--;
 | 
					        Changes._nextId--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const id = "node/" + osmNode.id;
 | 
					        const id = "node/" + newId;
 | 
				
			||||||
        osmNode.lat = lat;
 | 
					
 | 
				
			||||||
        osmNode.lon = lon;
 | 
					
 | 
				
			||||||
        const properties = {id: id};
 | 
					        const properties = {id: id};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const geojson = {
 | 
					        const geojson = {
 | 
				
			||||||
| 
						 | 
					@ -135,22 +140,32 @@ export class Changes implements FeatureSource {
 | 
				
			||||||
            properties["_backend"] = State.state.osmConnection.userDetails.data.backend
 | 
					            properties["_backend"] = State.state.osmConnection.userDetails.data.backend
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // this.uploadAll([osmNode], changes);
 | 
					
 | 
				
			||||||
 | 
					        this.newObjects.data.push({id: newId, lat: lat, lon: lon})
 | 
				
			||||||
 | 
					        this.pending.data.push(...changes)
 | 
				
			||||||
 | 
					        this.pending.ping();
 | 
				
			||||||
 | 
					        this.newObjects.ping();
 | 
				
			||||||
        return geojson;
 | 
					        return geojson;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private uploadChangesWithLatestVersions(
 | 
					    private uploadChangesWithLatestVersions(
 | 
				
			||||||
        knownElements: OsmObject[], newElements: OsmObject[], pending: { elementId: string; key: string; value: string }[]) {
 | 
					        knownElements: OsmObject[]) {
 | 
				
			||||||
        const knownById = new Map<string, OsmObject>();
 | 
					        const knownById = new Map<string, OsmObject>();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        knownElements.forEach(knownElement => {
 | 
					        knownElements.forEach(knownElement => {
 | 
				
			||||||
            knownById.set(knownElement.type + "/" + knownElement.id, knownElement)
 | 
					            knownById.set(knownElement.type + "/" + knownElement.id, knownElement)
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const newElements: OsmNode [] = this.newObjects.data.map(spec => {
 | 
				
			||||||
 | 
					            const newElement = new OsmNode(spec.id);
 | 
				
			||||||
 | 
					            newElement.lat = spec.lat;
 | 
				
			||||||
 | 
					            newElement.lon = spec.lon;
 | 
				
			||||||
 | 
					            return newElement
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Here, inside the continuation, we know that all 'neededIds' are loaded in 'knownElements', which maps the ids onto the elements
 | 
					        // Here, inside the continuation, we know that all 'neededIds' are loaded in 'knownElements', which maps the ids onto the elements
 | 
				
			||||||
        // We apply the changes on them
 | 
					        // We apply the changes on them
 | 
				
			||||||
        for (const change of pending) {
 | 
					        for (const change of this.pending.data) {
 | 
				
			||||||
            if (parseInt(change.elementId.split("/")[1]) < 0) {
 | 
					            if (parseInt(change.elementId.split("/")[1]) < 0) {
 | 
				
			||||||
                // This is a new element - we should apply this on one of the new elements
 | 
					                // This is a new element - we should apply this on one of the new elements
 | 
				
			||||||
                for (const newElement of newElements) {
 | 
					                for (const newElement of newElements) {
 | 
				
			||||||
| 
						 | 
					@ -217,17 +232,19 @@ export class Changes implements FeatureSource {
 | 
				
			||||||
                changes += "</osmChange>";
 | 
					                changes += "</osmChange>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return changes;
 | 
					                return changes;
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            () => {
 | 
				
			||||||
 | 
					                console.log("Upload successfull!")
 | 
				
			||||||
 | 
					                this.newObjects.setData([])
 | 
				
			||||||
 | 
					                this.pending.setData([]);
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private uploadAll(
 | 
					    private uploadAll() {
 | 
				
			||||||
        newElements: OsmObject[],
 | 
					 | 
				
			||||||
        pending: { elementId: string; key: string; value: string }[]
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        const self = this;
 | 
					        const self = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const pending = this.pending.data;
 | 
				
			||||||
        let neededIds: string[] = [];
 | 
					        let neededIds: string[] = [];
 | 
				
			||||||
        for (const change of pending) {
 | 
					        for (const change of pending) {
 | 
				
			||||||
            const id = change.elementId;
 | 
					            const id = change.elementId;
 | 
				
			||||||
| 
						 | 
					@ -240,8 +257,7 @@ export class Changes implements FeatureSource {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        neededIds = Utils.Dedup(neededIds);
 | 
					        neededIds = Utils.Dedup(neededIds);
 | 
				
			||||||
        OsmObject.DownloadAll(neededIds).addCallbackAndRunD(knownElements => {
 | 
					        OsmObject.DownloadAll(neededIds).addCallbackAndRunD(knownElements => {
 | 
				
			||||||
            console.log("KnownElements:", knownElements)
 | 
					            self.uploadChangesWithLatestVersions(knownElements)
 | 
				
			||||||
            self.uploadChangesWithLatestVersions(knownElements, newElements, pending)
 | 
					 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ export class ChangesetHandler {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static parseUploadChangesetResponse(response: XMLDocument, allElements: ElementStorage) {
 | 
					    private static parseUploadChangesetResponse(response: XMLDocument, allElements: ElementStorage) : void{
 | 
				
			||||||
        const nodes = response.getElementsByTagName("node");
 | 
					        const nodes = response.getElementsByTagName("node");
 | 
				
			||||||
        // @ts-ignore
 | 
					        // @ts-ignore
 | 
				
			||||||
        for (const node of nodes) {
 | 
					        for (const node of nodes) {
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,8 @@ export class ChangesetHandler {
 | 
				
			||||||
    public UploadChangeset(
 | 
					    public UploadChangeset(
 | 
				
			||||||
        layout: LayoutConfig,
 | 
					        layout: LayoutConfig,
 | 
				
			||||||
        allElements: ElementStorage,
 | 
					        allElements: ElementStorage,
 | 
				
			||||||
        generateChangeXML: (csid: string) => string) {
 | 
					        generateChangeXML: (csid: string) => string,
 | 
				
			||||||
 | 
					        whenDone : (csId: string) => void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.userDetails.data.csCount == 0) {
 | 
					        if (this.userDetails.data.csCount == 0) {
 | 
				
			||||||
            // The user became a contributor!
 | 
					            // The user became a contributor!
 | 
				
			||||||
| 
						 | 
					@ -80,6 +81,7 @@ export class ChangesetHandler {
 | 
				
			||||||
        if (this._dryRun) {
 | 
					        if (this._dryRun) {
 | 
				
			||||||
            const changesetXML = generateChangeXML("123456");
 | 
					            const changesetXML = generateChangeXML("123456");
 | 
				
			||||||
            console.log(changesetXML);
 | 
					            console.log(changesetXML);
 | 
				
			||||||
 | 
					            whenDone("123456")
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,8 +95,7 @@ export class ChangesetHandler {
 | 
				
			||||||
                console.log(changeset);
 | 
					                console.log(changeset);
 | 
				
			||||||
                self.AddChange(csId, changeset,
 | 
					                self.AddChange(csId, changeset,
 | 
				
			||||||
                    allElements,
 | 
					                    allElements,
 | 
				
			||||||
                    () => {
 | 
					                    whenDone,
 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    (e) => {
 | 
					                    (e) => {
 | 
				
			||||||
                        console.error("UPLOADING FAILED!", e)
 | 
					                        console.error("UPLOADING FAILED!", e)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					@ -107,14 +108,13 @@ export class ChangesetHandler {
 | 
				
			||||||
                csId,
 | 
					                csId,
 | 
				
			||||||
                generateChangeXML(csId),
 | 
					                generateChangeXML(csId),
 | 
				
			||||||
                allElements,
 | 
					                allElements,
 | 
				
			||||||
                () => {
 | 
					                whenDone,
 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                (e) => {
 | 
					                (e) => {
 | 
				
			||||||
                    console.warn("Could not upload, changeset is probably closed: ", e);
 | 
					                    console.warn("Could not upload, changeset is probably closed: ", e);
 | 
				
			||||||
                    // Mark the CS as closed...
 | 
					                    // Mark the CS as closed...
 | 
				
			||||||
                    this.currentChangeset.setData("");
 | 
					                    this.currentChangeset.setData("");
 | 
				
			||||||
                    // ... and try again. As the cs is closed, no recursive loop can exist  
 | 
					                    // ... and try again. As the cs is closed, no recursive loop can exist  
 | 
				
			||||||
                    self.UploadChangeset(layout, allElements, generateChangeXML);
 | 
					                    self.UploadChangeset(layout, allElements, generateChangeXML, whenDone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
| 
						 | 
					@ -244,7 +244,6 @@ export class ChangesetHandler {
 | 
				
			||||||
        }, function (err, response) {
 | 
					        }, function (err, response) {
 | 
				
			||||||
            if (response === undefined) {
 | 
					            if (response === undefined) {
 | 
				
			||||||
                console.log("err", err);
 | 
					                console.log("err", err);
 | 
				
			||||||
                alert("Could not upload change (opening failed). Please file a bug report")
 | 
					 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                continuation(response);
 | 
					                continuation(response);
 | 
				
			||||||
| 
						 | 
					@ -265,7 +264,7 @@ export class ChangesetHandler {
 | 
				
			||||||
    private AddChange(changesetId: string,
 | 
					    private AddChange(changesetId: string,
 | 
				
			||||||
                      changesetXML: string,
 | 
					                      changesetXML: string,
 | 
				
			||||||
                      allElements: ElementStorage,
 | 
					                      allElements: ElementStorage,
 | 
				
			||||||
                      continuation: ((changesetId: string, idMapping: any) => void),
 | 
					                      continuation: ((changesetId: string) => void),
 | 
				
			||||||
                      onFail: ((changesetId: string, reason: string) => void) = undefined) {
 | 
					                      onFail: ((changesetId: string, reason: string) => void) = undefined) {
 | 
				
			||||||
        this.auth.xhr({
 | 
					        this.auth.xhr({
 | 
				
			||||||
            method: 'POST',
 | 
					            method: 'POST',
 | 
				
			||||||
| 
						 | 
					@ -280,9 +279,9 @@ export class ChangesetHandler {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            const mapping = ChangesetHandler.parseUploadChangesetResponse(response, allElements);
 | 
					            ChangesetHandler.parseUploadChangesetResponse(response, allElements);
 | 
				
			||||||
            console.log("Uploaded changeset ", changesetId);
 | 
					            console.log("Uploaded changeset ", changesetId);
 | 
				
			||||||
            continuation(changesetId, mapping);
 | 
					            continuation(changesetId);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,8 +110,9 @@ export class OsmConnection {
 | 
				
			||||||
    public UploadChangeset(
 | 
					    public UploadChangeset(
 | 
				
			||||||
        layout: LayoutConfig,
 | 
					        layout: LayoutConfig,
 | 
				
			||||||
        allElements: ElementStorage,
 | 
					        allElements: ElementStorage,
 | 
				
			||||||
        generateChangeXML: (csid: string) => string) {
 | 
					        generateChangeXML: (csid: string) => string,
 | 
				
			||||||
        this.changesetHandler.UploadChangeset(layout, allElements, generateChangeXML);
 | 
					        whenDone: (csId: string) => void) {
 | 
				
			||||||
 | 
					        this.changesetHandler.UploadChangeset(layout, allElements, generateChangeXML, whenDone);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public GetPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource<string> {
 | 
					    public GetPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource<string> {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,8 @@ import {UIEventSource} from "../UIEventSource";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export abstract class OsmObject {
 | 
					export abstract class OsmObject {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected static backendURL = "https://www.openstreetmap.org/"
 | 
					    private static defaultBackend = "https://www.openstreetmap.org/"
 | 
				
			||||||
 | 
					    protected static backendURL = OsmObject.defaultBackend;
 | 
				
			||||||
    private static polygonFeatures = OsmObject.constructPolygonFeatures()
 | 
					    private static polygonFeatures = OsmObject.constructPolygonFeatures()
 | 
				
			||||||
    private static objectCache = new Map<string, UIEventSource<OsmObject>>();
 | 
					    private static objectCache = new Map<string, UIEventSource<OsmObject>>();
 | 
				
			||||||
    private static referencingWaysCache = new Map<string, UIEventSource<OsmWay[]>>();
 | 
					    private static referencingWaysCache = new Map<string, UIEventSource<OsmWay[]>>();
 | 
				
			||||||
| 
						 | 
					@ -37,15 +38,15 @@ export abstract class OsmObject {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static DownloadObject(id: string, forceRefresh: boolean = false): UIEventSource<OsmObject> {
 | 
					    static DownloadObject(id: string, forceRefresh: boolean = false): UIEventSource<OsmObject> {
 | 
				
			||||||
        let src : UIEventSource<OsmObject>;
 | 
					        let src: UIEventSource<OsmObject>;
 | 
				
			||||||
        if (OsmObject.objectCache.has(id)) {
 | 
					        if (OsmObject.objectCache.has(id)) {
 | 
				
			||||||
            src = OsmObject.objectCache.get(id)
 | 
					            src = OsmObject.objectCache.get(id)
 | 
				
			||||||
            if(forceRefresh){
 | 
					            if (forceRefresh) {
 | 
				
			||||||
                src.setData(undefined)
 | 
					                src.setData(undefined)
 | 
				
			||||||
            }else{
 | 
					            } else {
 | 
				
			||||||
                return src;
 | 
					                return src;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }else{
 | 
					        } else {
 | 
				
			||||||
            src = new UIEventSource<OsmObject>(undefined)
 | 
					            src = new UIEventSource<OsmObject>(undefined)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const splitted = id.split("/");
 | 
					        const splitted = id.split("/");
 | 
				
			||||||
| 
						 | 
					@ -157,7 +158,7 @@ export abstract class OsmObject {
 | 
				
			||||||
        const minlat = bounds[1][0]
 | 
					        const minlat = bounds[1][0]
 | 
				
			||||||
        const maxlat = bounds[0][0];
 | 
					        const maxlat = bounds[0][0];
 | 
				
			||||||
        const url = `${OsmObject.backendURL}api/0.6/map.json?bbox=${minlon},${minlat},${maxlon},${maxlat}`
 | 
					        const url = `${OsmObject.backendURL}api/0.6/map.json?bbox=${minlon},${minlat},${maxlon},${maxlat}`
 | 
				
			||||||
        Utils.downloadJson(url).then( data => {
 | 
					        Utils.downloadJson(url).then(data => {
 | 
				
			||||||
            const elements: any[] = data.elements;
 | 
					            const elements: any[] = data.elements;
 | 
				
			||||||
            const objects = OsmObject.ParseObjects(elements)
 | 
					            const objects = OsmObject.ParseObjects(elements)
 | 
				
			||||||
            callback(objects);
 | 
					            callback(objects);
 | 
				
			||||||
| 
						 | 
					@ -291,6 +292,7 @@ export abstract class OsmObject {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                self.LoadData(element)
 | 
					                self.LoadData(element)
 | 
				
			||||||
                self.SaveExtraData(element, nodes);
 | 
					                self.SaveExtraData(element, nodes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const meta = {
 | 
					                const meta = {
 | 
				
			||||||
                    "_last_edit:contributor": element.user,
 | 
					                    "_last_edit:contributor": element.user,
 | 
				
			||||||
                    "_last_edit:contributor:uid": element.uid,
 | 
					                    "_last_edit:contributor:uid": element.uid,
 | 
				
			||||||
| 
						 | 
					@ -299,6 +301,11 @@ export abstract class OsmObject {
 | 
				
			||||||
                    "_version_number": element.version
 | 
					                    "_version_number": element.version
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (OsmObject.backendURL !== OsmObject.defaultBackend) {
 | 
				
			||||||
 | 
					                    self.tags["_backend"] = OsmObject.backendURL
 | 
				
			||||||
 | 
					                    meta["_backend"] = OsmObject.backendURL;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                continuation(self, meta);
 | 
					                continuation(self, meta);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,22 @@ import {UIEventSource} from "../UIEventSource";
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export class LocalStorageSource {
 | 
					export class LocalStorageSource {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    static GetParsed(key: string, defaultValue : any){
 | 
				
			||||||
 | 
					        return LocalStorageSource.Get(key).map(
 | 
				
			||||||
 | 
					            str => {
 | 
				
			||||||
 | 
					                if(str === undefined){
 | 
				
			||||||
 | 
					                    return defaultValue
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                try{
 | 
				
			||||||
 | 
					                    return JSON.parse(str)
 | 
				
			||||||
 | 
					                }catch{
 | 
				
			||||||
 | 
					                    return defaultValue
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }, [], 
 | 
				
			||||||
 | 
					            value => JSON.stringify(value)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static Get(key: string, defaultValue: string = undefined): UIEventSource<string> {
 | 
					    static Get(key: string, defaultValue: string = undefined): UIEventSource<string> {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            const saved = localStorage.getItem(key);
 | 
					            const saved = localStorage.getItem(key);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ import { Utils } from "../Utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class Constants {
 | 
					export default class Constants {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public static vNumber = "0.8.3d";
 | 
					    public static vNumber = "0.8.4";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // The user journey states thresholds when a new feature gets unlocked
 | 
					    // The user journey states thresholds when a new feature gets unlocked
 | 
				
			||||||
    public static userJourney = {
 | 
					    public static userJourney = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,8 +59,12 @@
 | 
				
			||||||
    "render": "<a href='https://openstreetmap.org/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'/></a>",
 | 
					    "render": "<a href='https://openstreetmap.org/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'/></a>",
 | 
				
			||||||
    "mappings": [
 | 
					    "mappings": [
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        "if": "id~=-",
 | 
					        "if": "id~.*/-.*",
 | 
				
			||||||
        "then": "<span class='alert'>Uploading...</alert>"
 | 
					        "then": ""
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "if": "_backend~*",
 | 
				
			||||||
 | 
					        "then": "<a href='{_backend}/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'/></a>"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "condition": "id~(node|way|relation)/[0-9]*"
 | 
					    "condition": "id~(node|way|relation)/[0-9]*"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue