diff --git a/src/Logic/Actors/InitialMapPositioning.ts b/src/Logic/Actors/InitialMapPositioning.ts index d61ab3803..7e4ce6d88 100644 --- a/src/Logic/Actors/InitialMapPositioning.ts +++ b/src/Logic/Actors/InitialMapPositioning.ts @@ -4,10 +4,12 @@ import { LocalStorageSource } from "../Web/LocalStorageSource" import { QueryParameters } from "../Web/QueryParameters" import Hash from "../Web/Hash" import OsmObjectDownloader from "../Osm/OsmObjectDownloader" -import { OsmObject } from "../Osm/OsmObject" import Constants from "../../Models/Constants" import { Utils } from "../../Utils" import { GeoLocationState } from "../State/GeoLocationState" +import { OsmConnection } from "../Osm/OsmConnection" + +"use strict" /** * This actor is responsible to set the map location. @@ -25,7 +27,7 @@ export default class InitialMapPositioning { public location: UIEventSource<{ lon: number; lat: number }> public useTerrain: Store - constructor(layoutToUse: ThemeConfig, geolocationState: GeoLocationState) { + constructor(layoutToUse: ThemeConfig, geolocationState: GeoLocationState, osmConnection: OsmConnection) { function localStorageSynced( key: string, deflt: number, @@ -47,7 +49,6 @@ export default class InitialMapPositioning { return src } - const initialHash = Hash.hash.data // -- Location control initialization this.zoom = localStorageSynced( @@ -72,6 +73,7 @@ export default class InitialMapPositioning { }) this.useTerrain = new ImmutableStore(layoutToUse.enableTerrain) + const initialHash = Hash.hash.data if (initialHash?.match(/^(node|way|relation)\/[0-9]+$/)) { // We pan to the selected element const [type, id] = initialHash.split("/") @@ -88,6 +90,15 @@ export default class InitialMapPositioning { const [lat, lon] = osmObject.centerpoint() this.location.setData({ lon, lat }) }) + } else if (layoutToUse.id === "notes" && initialHash?.match(/[0-9]+/)) { + console.log("Loading note", initialHash) + const noteId = Number(initialHash) + osmConnection.getNote(noteId).then(note => { + const [lon, lat] = note.geometry.coordinates + console.log("Got note:", note) + this.location.set({ lon, lat }) + } + ) } else if ( Constants.GeoIpServer && lat.data === defaultLat && diff --git a/src/Logic/Osm/OsmConnection.ts b/src/Logic/Osm/OsmConnection.ts index 4ee3b73b7..8c30df86f 100644 --- a/src/Logic/Osm/OsmConnection.ts +++ b/src/Logic/Osm/OsmConnection.ts @@ -5,6 +5,7 @@ import { Utils } from "../../Utils" import { LocalStorageSource } from "../Web/LocalStorageSource" import { AuthConfig } from "./AuthConfig" import Constants from "../../Models/Constants" +import { Feature, Point } from "geojson" interface OsmUserInfo { id: number @@ -218,7 +219,7 @@ export class OsmConnection { this.auth.xhr( { method: "GET", - path: "/api/0.6/user/details", + path: "/api/0.6/user/details" }, (err, details: XMLDocument) => { if (err != null) { @@ -330,9 +331,9 @@ export class OsmConnection { method, headers: header, content, - path: `/api/0.6/${path}`, + path: `/api/0.6/${path}` }, - function (err, response) { + function(err, response) { if (err !== null) { error(err) } else { @@ -412,7 +413,7 @@ export class OsmConnection { "notes.json", content, { - "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" }, true ) @@ -423,6 +424,12 @@ export class OsmConnection { return id } + public async getNote(id: number): Promise> { + return JSON.parse(await this.get( + "notes/" + id + ".json" + )) + } + public static GpxTrackVisibility = ["private", "public", "trackable", "identifiable"] as const public async uploadGpxTrack( @@ -453,7 +460,7 @@ export class OsmConnection { file: gpx, description: options.description, tags: options.labels?.join(",") ?? "", - visibility: options.visibility, + visibility: options.visibility } if (!contents.description) { @@ -461,9 +468,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" @@ -471,7 +478,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] } @@ -482,7 +489,7 @@ export class OsmConnection { const response = await this.post("gpx/create", body, { "Content-Type": "multipart/form-data; boundary=" + boundary, - "Content-Length": "" + body.length, + "Content-Length": "" + body.length }) const parsed = JSON.parse(response) console.log("Uploaded GPX track", parsed) @@ -503,9 +510,9 @@ export class OsmConnection { { method: "POST", - path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`, + path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}` }, - function (err) { + function(err) { if (err !== null) { error(err) } else { @@ -520,7 +527,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") @@ -541,7 +548,7 @@ export class OsmConnection { */ singlepage: !this._iframeMode, auto: true, - apiUrl: this._oauth_config.api_url ?? this._oauth_config.url, + apiUrl: this._oauth_config.api_url ?? this._oauth_config.url }) } diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index 8fece162b..9fed80d7d 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -2,11 +2,7 @@ import ThemeConfig from "./ThemeConfig/ThemeConfig" import { SpecialVisualizationState } from "../UI/SpecialVisualization" import { Changes } from "../Logic/Osm/Changes" import { Store, UIEventSource } from "../Logic/UIEventSource" -import { - FeatureSource, - IndexedFeatureSource, - WritableFeatureSource, -} from "../Logic/FeatureSource/FeatureSource" +import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource" import { OsmConnection } from "../Logic/Osm/OsmConnection" import { ExportableMap, MapProperties } from "./MapProperties" import LayerState from "../Logic/State/LayerState" @@ -50,9 +46,7 @@ import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter" import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage" import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource" import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor" -import NoElementsInViewDetector, { - FeatureViewState, -} from "../Logic/Actors/NoElementsInViewDetector" +import NoElementsInViewDetector, { FeatureViewState } from "../Logic/Actors/NoElementsInViewDetector" import FilteredLayer from "./FilteredLayer" import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector" import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager" @@ -63,7 +57,7 @@ import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl" import Zoomcontrol from "../UI/Zoomcontrol" import { SummaryTileSource, - SummaryTileSourceRewriter, + SummaryTileSourceRewriter } from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource" import summaryLayer from "../assets/generated/layers/summary.json" import last_click_layerconfig from "../assets/generated/layers/last_click.json" @@ -177,12 +171,6 @@ export default class ThemeViewState implements SpecialVisualizationState { ) this.map = new UIEventSource(undefined) const geolocationState = new GeoLocationState() - const initial = new InitialMapPositioning(layout, geolocationState) - this.mapProperties = new MapLibreAdaptor(this.map, initial, { correctClick: 20 }) - - this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting - this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin - this.osmConnection = new OsmConnection({ dryRun: this.featureSwitches.featureSwitchIsTesting, fakeUser: this.featureSwitches.featureSwitchFakeUser.data, @@ -190,8 +178,15 @@ export default class ThemeViewState implements SpecialVisualizationState { "oauth_token", undefined, "Used to complete the login" - ), + ) }) + const initial = new InitialMapPositioning(layout, geolocationState, this.osmConnection) + this.mapProperties = new MapLibreAdaptor(this.map, initial, { correctClick: 20 }) + + this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting + this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin + + this.userRelatedState = new UserRelatedState( this.osmConnection, layout, @@ -788,7 +783,7 @@ export default class ThemeViewState implements SpecialVisualizationState { const layers = this.theme.layers.filter( (l) => - Constants.priviliged_layers.indexOf(l.id) < 0 && + (Constants.priviliged_layers).indexOf(l.id) < 0 && l.source.geojsonSource === undefined && l.doCount ) @@ -840,7 +835,7 @@ export default class ThemeViewState implements SpecialVisualizationState { this.closestFeatures.registerSource(specialLayers.favourite, "favourite") if (this.theme?.lockLocation) { - const bbox = new BBox(this.theme.lockLocation) + const bbox = new BBox(<[[number, number], [number, number]]>this.theme.lockLocation) this.mapProperties.maxbounds.setData(bbox) ShowDataLayer.showRange( this.map,