forked from MapComplete/MapComplete
Chore: housekeeping
This commit is contained in:
parent
cd9e03dd6f
commit
b300fffdc5
156 changed files with 4436 additions and 1318 deletions
|
|
@ -13,7 +13,6 @@ import StaticFeatureSource, {
|
|||
} from "../FeatureSource/Sources/StaticFeatureSource"
|
||||
import { MapProperties } from "../../Models/MapProperties"
|
||||
import { Orientation } from "../../Sensors/Orientation"
|
||||
|
||||
;("use strict")
|
||||
/**
|
||||
* The geolocation-handler takes a map-location and a geolocation state.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { bbox } from "@turf/bbox"
|
|||
export class BBox {
|
||||
static global: BBox = new BBox([
|
||||
[-180, -90],
|
||||
[180, 90]
|
||||
[180, 90],
|
||||
])
|
||||
readonly maxLat: number
|
||||
readonly maxLon: number
|
||||
|
|
@ -62,7 +62,7 @@ export class BBox {
|
|||
static fromLeafletBounds(bounds) {
|
||||
return new BBox([
|
||||
[bounds.getWest(), bounds.getNorth()],
|
||||
[bounds.getEast(), bounds.getSouth()]
|
||||
[bounds.getEast(), bounds.getSouth()],
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ export class BBox {
|
|||
}
|
||||
return new BBox([
|
||||
[maxLon, maxLat],
|
||||
[minLon, minLat]
|
||||
[minLon, minLat],
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ export class BBox {
|
|||
public unionWith(other: BBox) {
|
||||
return new BBox([
|
||||
[Math.max(this.maxLon, other.maxLon), Math.max(this.maxLat, other.maxLat)],
|
||||
[Math.min(this.minLon, other.minLon), Math.min(this.minLat, other.minLat)]
|
||||
[Math.min(this.minLon, other.minLon), Math.min(this.minLat, other.minLat)],
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ export class BBox {
|
|||
|
||||
return new BBox([
|
||||
[lon - s / 2, lat - s / 2],
|
||||
[lon + s / 2, lat + s / 2]
|
||||
[lon + s / 2, lat + s / 2],
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -238,21 +238,21 @@ export class BBox {
|
|||
const lonDiff = Math.min(maxIncrease / 2, Math.abs(this.maxLon - this.minLon) * factor)
|
||||
return new BBox([
|
||||
[this.minLon - lonDiff, this.minLat - latDiff],
|
||||
[this.maxLon + lonDiff, this.maxLat + latDiff]
|
||||
[this.maxLon + lonDiff, this.maxLat + latDiff],
|
||||
])
|
||||
}
|
||||
|
||||
padAbsolute(degrees: number): BBox {
|
||||
return new BBox([
|
||||
[this.minLon - degrees, this.minLat - degrees],
|
||||
[this.maxLon + degrees, this.maxLat + degrees]
|
||||
[this.maxLon + degrees, this.maxLat + degrees],
|
||||
])
|
||||
}
|
||||
|
||||
toLngLat(): [[number, number], [number, number]] {
|
||||
return [
|
||||
[this.minLon, this.minLat],
|
||||
[this.maxLon, this.maxLat]
|
||||
[this.maxLon, this.maxLat],
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +271,7 @@ export class BBox {
|
|||
return {
|
||||
type: "Feature",
|
||||
properties: properties,
|
||||
geometry: this.asGeometry()
|
||||
geometry: this.asGeometry(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,9 +284,9 @@ export class BBox {
|
|||
[this.maxLon, this.minLat],
|
||||
[this.maxLon, this.maxLat],
|
||||
[this.minLon, this.maxLat],
|
||||
[this.minLon, this.minLat]
|
||||
]
|
||||
]
|
||||
[this.minLon, this.minLat],
|
||||
],
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +316,7 @@ export class BBox {
|
|||
minLon,
|
||||
maxLon,
|
||||
minLat,
|
||||
maxLat
|
||||
maxLat,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,21 +77,34 @@ export default class SaveFeatureSourceToLocalStorage {
|
|||
this.storage = storage
|
||||
const singleTileSavers: Map<number, SingleTileSaver> = new Map<number, SingleTileSaver>()
|
||||
features.features.addCallbackAndRunD((features) => {
|
||||
if (features.some(f => {
|
||||
let totalPoints = 0
|
||||
if (f.geometry.type === "MultiPolygon") {
|
||||
totalPoints = f.geometry.coordinates.map(rings => rings.map(ring => ring.length).reduce((a, b) => a + b)).reduce((a, b) => a + b)
|
||||
} else if (f.geometry.type === "Polygon" || f.geometry.type === "MultiLineString") {
|
||||
totalPoints = f.geometry.coordinates.map(ring => ring.length).reduce((a, b) => a + b)
|
||||
} else if (f.geometry.type === "LineString") {
|
||||
totalPoints = f.geometry.coordinates.length
|
||||
}
|
||||
if (totalPoints > 1000) {
|
||||
console.warn(`Not caching tiles, detected a big object (${totalPoints} points for ${f.properties.id})`)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})) {
|
||||
if (
|
||||
features.some((f) => {
|
||||
let totalPoints = 0
|
||||
if (f.geometry.type === "MultiPolygon") {
|
||||
totalPoints = f.geometry.coordinates
|
||||
.map((rings) =>
|
||||
rings.map((ring) => ring.length).reduce((a, b) => a + b)
|
||||
)
|
||||
.reduce((a, b) => a + b)
|
||||
} else if (
|
||||
f.geometry.type === "Polygon" ||
|
||||
f.geometry.type === "MultiLineString"
|
||||
) {
|
||||
totalPoints = f.geometry.coordinates
|
||||
.map((ring) => ring.length)
|
||||
.reduce((a, b) => a + b)
|
||||
} else if (f.geometry.type === "LineString") {
|
||||
totalPoints = f.geometry.coordinates.length
|
||||
}
|
||||
if (totalPoints > 1000) {
|
||||
console.warn(
|
||||
`Not caching tiles, detected a big object (${totalPoints} points for ${f.properties.id})`
|
||||
)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
) {
|
||||
// Has big objects
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,11 @@ export default class DynamicGeoJsonTileSource extends UpdatableDynamicTileSource
|
|||
if (DynamicGeoJsonTileSource.whitelistCache.has(whitelistUrl)) {
|
||||
whitelist = DynamicGeoJsonTileSource.whitelistCache.get(whitelistUrl)
|
||||
} else {
|
||||
Utils.downloadJsonCached<Record<string | number, number[]>>(whitelistUrl, 1000 * 60 * 60)
|
||||
.then(json => {
|
||||
Utils.downloadJsonCached<Record<string | number, number[]>>(
|
||||
whitelistUrl,
|
||||
1000 * 60 * 60
|
||||
)
|
||||
.then((json) => {
|
||||
const data = new Map<number, Set<number>>()
|
||||
for (const x in json) {
|
||||
if (x === "zoom") {
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import {
|
|||
MultiPolygon,
|
||||
Point,
|
||||
Polygon,
|
||||
Position
|
||||
Position,
|
||||
} from "geojson"
|
||||
import { Tiles } from "../Models/TileRange"
|
||||
import { Utils } from "../Utils"
|
||||
|
||||
("use strict")
|
||||
;("use strict")
|
||||
|
||||
export class GeoOperations {
|
||||
private static readonly _earthRadius = 6378137
|
||||
|
|
@ -29,7 +29,7 @@ export class GeoOperations {
|
|||
"behind",
|
||||
"sharp_left",
|
||||
"left",
|
||||
"slight_left"
|
||||
"slight_left",
|
||||
] as const
|
||||
private static reverseBearing = {
|
||||
N: 0,
|
||||
|
|
@ -47,7 +47,7 @@ export class GeoOperations {
|
|||
W: 270,
|
||||
WNW: 292.5,
|
||||
NW: 315,
|
||||
NNW: 337.5
|
||||
NNW: 337.5,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -309,7 +309,7 @@ export class GeoOperations {
|
|||
bufferSizeInMeter: number
|
||||
): Feature<Polygon | MultiPolygon> | FeatureCollection<Polygon | MultiPolygon> {
|
||||
return turf.buffer(feature, bufferSizeInMeter / 1000, {
|
||||
units: "kilometers"
|
||||
units: "kilometers",
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -325,9 +325,9 @@ export class GeoOperations {
|
|||
[lon0, lat],
|
||||
[lon0, lat0],
|
||||
[lon, lat0],
|
||||
[lon, lat]
|
||||
]
|
||||
}
|
||||
[lon, lat],
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +345,10 @@ export class GeoOperations {
|
|||
public static nearestPoint(
|
||||
way: Feature<LineString>,
|
||||
point: [number, number]
|
||||
): Feature<Point, { dist: number; index: number; multiFeatureIndex: number; location: number }> {
|
||||
): Feature<
|
||||
Point,
|
||||
{ dist: number; index: number; multiFeatureIndex: number; location: number }
|
||||
> {
|
||||
return turf.nearestPointOnLine(<Feature<LineString>>way, point, { units: "kilometers" })
|
||||
}
|
||||
|
||||
|
|
@ -368,9 +371,9 @@ export class GeoOperations {
|
|||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: way.geometry.coordinates[0]
|
||||
coordinates: way.geometry.coordinates[0],
|
||||
},
|
||||
properties: way.properties
|
||||
properties: way.properties,
|
||||
}
|
||||
}
|
||||
if (way.geometry.type === "MultiPolygon") {
|
||||
|
|
@ -378,9 +381,9 @@ export class GeoOperations {
|
|||
type: "Feature",
|
||||
geometry: {
|
||||
type: "MultiLineString",
|
||||
coordinates: way.geometry.coordinates[0]
|
||||
coordinates: way.geometry.coordinates[0],
|
||||
},
|
||||
properties: way.properties
|
||||
properties: way.properties,
|
||||
}
|
||||
}
|
||||
if (way.geometry.type === "LineString") {
|
||||
|
|
@ -542,7 +545,10 @@ export class GeoOperations {
|
|||
* Note: IDs are rewritten
|
||||
* Also @see spreadIntoBBoxes
|
||||
*/
|
||||
public static clipAllInBox(features: ReadonlyArray<Readonly<Feature>>, tileIndex: number): Feature[] {
|
||||
public static clipAllInBox(
|
||||
features: ReadonlyArray<Readonly<Feature>>,
|
||||
tileIndex: number
|
||||
): Feature[] {
|
||||
const bbox = Tiles.asGeojson(tileIndex)
|
||||
const newFeatures: Feature[] = []
|
||||
for (const f of features) {
|
||||
|
|
@ -555,7 +561,7 @@ export class GeoOperations {
|
|||
}
|
||||
const properties = {
|
||||
...f.properties,
|
||||
id
|
||||
id,
|
||||
}
|
||||
intersectionPart.properties = properties
|
||||
newFeatures.push(intersectionPart)
|
||||
|
|
@ -587,8 +593,8 @@ export class GeoOperations {
|
|||
properties: {},
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: p
|
||||
}
|
||||
coordinates: p,
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -604,7 +610,7 @@ export class GeoOperations {
|
|||
trackPoints.push(trkpt)
|
||||
}
|
||||
const header =
|
||||
"<gpx version=\"1.1\" creator=\"mapcomplete.org\" xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">"
|
||||
'<gpx version="1.1" creator="mapcomplete.org" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">'
|
||||
return (
|
||||
header +
|
||||
"\n<name>" +
|
||||
|
|
@ -643,7 +649,7 @@ export class GeoOperations {
|
|||
trackPoints.push(trkpt)
|
||||
}
|
||||
const header =
|
||||
"<gpx version=\"1.1\" creator=\"mapcomplete.org\" xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">"
|
||||
'<gpx version="1.1" creator="mapcomplete.org" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">'
|
||||
return (
|
||||
header +
|
||||
"\n<name>" +
|
||||
|
|
@ -669,7 +675,7 @@ export class GeoOperations {
|
|||
|
||||
const copy = {
|
||||
...feature,
|
||||
geometry: { ...feature.geometry }
|
||||
geometry: { ...feature.geometry },
|
||||
}
|
||||
let coordinates: [number, number][]
|
||||
if (feature.geometry.type === "LineString") {
|
||||
|
|
@ -727,8 +733,8 @@ export class GeoOperations {
|
|||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: [a, b]
|
||||
}
|
||||
coordinates: [a, b],
|
||||
},
|
||||
},
|
||||
distanceMeter,
|
||||
{ units: "meters" }
|
||||
|
|
@ -769,13 +775,17 @@ export class GeoOperations {
|
|||
possiblyEnclosingFeature: Readonly<Feature<Polygon | MultiPolygon>>
|
||||
): boolean {
|
||||
if (feature.geometry.type === "MultiPolygon") {
|
||||
const polygons = feature.geometry.coordinates.map(coordinates =>
|
||||
<Feature<Polygon>>{
|
||||
type: "Feature", geometry: {
|
||||
type: "Polygon", coordinates
|
||||
const polygons = feature.geometry.coordinates.map(
|
||||
(coordinates) =>
|
||||
<Feature<Polygon>>{
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates,
|
||||
},
|
||||
}
|
||||
})
|
||||
return !polygons.some(polygon => !booleanWithin(polygon, possiblyEnclosingFeature))
|
||||
)
|
||||
return !polygons.some((polygon) => !booleanWithin(polygon, possiblyEnclosingFeature))
|
||||
}
|
||||
return booleanWithin(feature, possiblyEnclosingFeature)
|
||||
}
|
||||
|
|
@ -784,7 +794,10 @@ export class GeoOperations {
|
|||
* Create an intersection between two features.
|
||||
* One or multiple new feature are returned based on 'toSplit', which'll have a geometry that is completely withing boundary
|
||||
*/
|
||||
public static clipWith(toSplit: Readonly<Feature>, boundary: Readonly<Feature<Polygon>>): Feature[] {
|
||||
public static clipWith(
|
||||
toSplit: Readonly<Feature>,
|
||||
boundary: Readonly<Feature<Polygon>>
|
||||
): Feature[] {
|
||||
if (toSplit.geometry.type === "Point") {
|
||||
const p = <Feature<Point>>toSplit
|
||||
if (GeoOperations.inside(<[number, number]>p.geometry.coordinates, boundary)) {
|
||||
|
|
@ -795,7 +808,10 @@ export class GeoOperations {
|
|||
}
|
||||
|
||||
if (toSplit.geometry.type === "LineString") {
|
||||
const splitup: Feature<LineString>[] = turf.lineSplit(<Feature<LineString>>toSplit, boundary).features
|
||||
const splitup: Feature<LineString>[] = turf.lineSplit(
|
||||
<Feature<LineString>>toSplit,
|
||||
boundary
|
||||
).features
|
||||
const kept: Feature[] = []
|
||||
for (const f of splitup) {
|
||||
if (!GeoOperations.inside(GeoOperations.centerpointCoordinates(f), boundary)) {
|
||||
|
|
@ -825,21 +841,29 @@ export class GeoOperations {
|
|||
return kept
|
||||
}
|
||||
if (toSplit.geometry.type === "Polygon" || toSplit.geometry.type == "MultiPolygon") {
|
||||
|
||||
const splitup = turf.intersect(turf.featureCollection([<Feature<Polygon | MultiPolygon>>toSplit, boundary]))
|
||||
const splitup = turf.intersect(
|
||||
turf.featureCollection([<Feature<Polygon | MultiPolygon>>toSplit, boundary])
|
||||
)
|
||||
if (splitup === null) {
|
||||
// No intersection found.
|
||||
// Either: the boundary is contained fully in 'toSplit', 'toSplit' is contained fully in 'boundary' or they are unrelated at all
|
||||
if (GeoOperations.completelyWithin(toSplit, boundary)) {
|
||||
return [toSplit]
|
||||
}
|
||||
if (GeoOperations.completelyWithin(boundary, <Feature<Polygon | MultiPolygon>>toSplit)) {
|
||||
return [{
|
||||
type: "Feature",
|
||||
properties: { ...toSplit.properties },
|
||||
geometry: boundary.geometry,
|
||||
bbox: boundary.bbox
|
||||
}]
|
||||
if (
|
||||
GeoOperations.completelyWithin(
|
||||
boundary,
|
||||
<Feature<Polygon | MultiPolygon>>toSplit
|
||||
)
|
||||
) {
|
||||
return [
|
||||
{
|
||||
type: "Feature",
|
||||
properties: { ...toSplit.properties },
|
||||
geometry: boundary.geometry,
|
||||
bbox: boundary.bbox,
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
|
@ -911,7 +935,9 @@ export class GeoOperations {
|
|||
return undefined
|
||||
case "end":
|
||||
if (feature.geometry.type === "LineString") {
|
||||
return <[number, number]>(<Feature<LineString>>feature).geometry.coordinates.at(-1)
|
||||
return <[number, number]>(
|
||||
(<Feature<LineString>>feature).geometry.coordinates.at(-1)
|
||||
)
|
||||
}
|
||||
return undefined
|
||||
default:
|
||||
|
|
@ -934,8 +960,8 @@ export class GeoOperations {
|
|||
properties: p.properties,
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: p.geometry.coordinates[0]
|
||||
}
|
||||
coordinates: p.geometry.coordinates[0],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -963,7 +989,7 @@ export class GeoOperations {
|
|||
console.debug("Splitting way", feature.properties.id)
|
||||
result.push(<Feature>{
|
||||
...feature,
|
||||
geometry: { ...feature.geometry, coordinates: coors.slice(i + 1) }
|
||||
geometry: { ...feature.geometry, coordinates: coors.slice(i + 1) },
|
||||
})
|
||||
coors = coors.slice(0, i + 1)
|
||||
break
|
||||
|
|
@ -972,7 +998,7 @@ export class GeoOperations {
|
|||
}
|
||||
result.push(<Feature>{
|
||||
...feature,
|
||||
geometry: { ...feature.geometry, coordinates: coors }
|
||||
geometry: { ...feature.geometry, coordinates: coors },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1146,8 +1172,8 @@ export class GeoOperations {
|
|||
properties: multiLineStringFeature.properties,
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: coors[0]
|
||||
}
|
||||
coordinates: coors[0],
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
|
@ -1155,8 +1181,8 @@ export class GeoOperations {
|
|||
properties: multiLineStringFeature.properties,
|
||||
geometry: {
|
||||
type: "MultiLineString",
|
||||
coordinates: coors
|
||||
}
|
||||
coordinates: coors,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1306,9 +1332,10 @@ export class GeoOperations {
|
|||
}
|
||||
if (e.message.indexOf("SweepLine tree") >= 0) {
|
||||
console.log("Applying fallback intersection...")
|
||||
const intersection = turf.intersect(turf.featureCollection([
|
||||
const intersection = turf.intersect(
|
||||
turf.featureCollection([
|
||||
turf.truncate(feature),
|
||||
turf.truncate(otherFeature)
|
||||
turf.truncate(otherFeature),
|
||||
])
|
||||
)
|
||||
if (intersection == null) {
|
||||
|
|
|
|||
|
|
@ -83,11 +83,15 @@ export default class AllImageProviders {
|
|||
): number {
|
||||
let count = 0
|
||||
|
||||
const sources = [Imgur.singleton,
|
||||
const sources = [
|
||||
Imgur.singleton,
|
||||
Mapillary.singleton,
|
||||
Panoramax.singleton,
|
||||
AllImageProviders.genericImageProvider]
|
||||
const allPrefixes = Utils.Dedup(prefixes ?? [].concat(...sources.map(s => s.defaultKeyPrefixes)))
|
||||
AllImageProviders.genericImageProvider,
|
||||
]
|
||||
const allPrefixes = Utils.Dedup(
|
||||
prefixes ?? [].concat(...sources.map((s) => s.defaultKeyPrefixes))
|
||||
)
|
||||
for (const prefix of allPrefixes) {
|
||||
for (const k in tags) {
|
||||
if (!tags[k]) {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
lat: number
|
||||
}
|
||||
): BaseUIElement {
|
||||
const host = ("https://" + new URL(img.url).host)
|
||||
const host = "https://" + new URL(img.url).host
|
||||
const p = new Panoramax(host)
|
||||
return new Link(
|
||||
new SvelteUIElement(Panoramax_bw),
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export class ChangesetHandler {
|
|||
| { addAlias: (id0: string, id1: string) => void }
|
||||
| undefined,
|
||||
changes: Changes,
|
||||
reportError: (e: string | Error, extramessage: string) => void,
|
||||
reportError: (e: string | Error, extramessage: string) => void
|
||||
) {
|
||||
this.osmConnection = osmConnection
|
||||
this._reportError = reportError
|
||||
|
|
@ -114,7 +114,7 @@ export class ChangesetHandler {
|
|||
private async UploadWithNew(
|
||||
generateChangeXML: (csid: number, remappings: Map<string, string>) => string,
|
||||
openChangeset: UIEventSource<number>,
|
||||
extraMetaTags: ChangesetTag[],
|
||||
extraMetaTags: ChangesetTag[]
|
||||
) {
|
||||
const csId = await this.OpenChangeset(extraMetaTags)
|
||||
openChangeset.setData(csId)
|
||||
|
|
@ -122,7 +122,7 @@ export class ChangesetHandler {
|
|||
console.log(
|
||||
"Opened a new changeset (openChangeset.data is undefined):",
|
||||
changeset,
|
||||
extraMetaTags,
|
||||
extraMetaTags
|
||||
)
|
||||
const changes = await this.UploadChange(csId, changeset)
|
||||
const hasSpecialMotivationChanges = ChangesetHandler.rewriteMetaTags(extraMetaTags, changes)
|
||||
|
|
@ -145,7 +145,7 @@ export class ChangesetHandler {
|
|||
public async UploadChangeset(
|
||||
generateChangeXML: (csid: number, remappings: Map<string, string>) => string,
|
||||
extraMetaTags: ChangesetTag[],
|
||||
openChangeset: UIEventSource<number>,
|
||||
openChangeset: UIEventSource<number>
|
||||
): Promise<void> {
|
||||
if (
|
||||
!extraMetaTags.some((tag) => tag.key === "comment") ||
|
||||
|
|
@ -180,13 +180,13 @@ export class ChangesetHandler {
|
|||
try {
|
||||
const rewritings = await this.UploadChange(
|
||||
csId,
|
||||
generateChangeXML(csId, this._remappings),
|
||||
generateChangeXML(csId, this._remappings)
|
||||
)
|
||||
|
||||
const rewrittenTags = this.RewriteTagsOf(
|
||||
extraMetaTags,
|
||||
rewritings,
|
||||
oldChangesetMeta,
|
||||
oldChangesetMeta
|
||||
)
|
||||
await this.UpdateTags(csId, rewrittenTags)
|
||||
return // We are done!
|
||||
|
|
@ -197,7 +197,7 @@ export class ChangesetHandler {
|
|||
} catch (e) {
|
||||
this._reportError(
|
||||
e,
|
||||
"While getting metadata from a changeset " + openChangeset.data,
|
||||
"While getting metadata from a changeset " + openChangeset.data
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -225,7 +225,7 @@ export class ChangesetHandler {
|
|||
console.warn(
|
||||
"Could not open/upload changeset due to ",
|
||||
e,
|
||||
"trying again with a another fresh changeset ",
|
||||
"trying again with a another fresh changeset "
|
||||
)
|
||||
openChangeset.setData(undefined)
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ export class ChangesetHandler {
|
|||
uid: number // User ID
|
||||
changes_count: number
|
||||
tags: any
|
||||
},
|
||||
}
|
||||
): ChangesetTag[] {
|
||||
// Note: extraMetaTags is where all the tags are collected into
|
||||
|
||||
|
|
@ -388,7 +388,7 @@ export class ChangesetHandler {
|
|||
tag.key !== undefined &&
|
||||
tag.value !== undefined &&
|
||||
tag.key !== "" &&
|
||||
tag.value !== "",
|
||||
tag.value !== ""
|
||||
)
|
||||
const metadata = tags.map((kv) => `<tag k="${kv.key}" v="${escapeHtml(kv.value)}"/>`)
|
||||
const content = [`<osm><changeset>`, metadata, `</changeset></osm>`].join("")
|
||||
|
|
@ -434,7 +434,7 @@ export class ChangesetHandler {
|
|||
const csId = await this.osmConnection.put(
|
||||
"changeset/create",
|
||||
[`<osm><changeset>`, metadata, `</changeset></osm>`].join(""),
|
||||
{ "Content-Type": "text/xml" },
|
||||
{ "Content-Type": "text/xml" }
|
||||
)
|
||||
return Number(csId)
|
||||
}
|
||||
|
|
@ -444,12 +444,12 @@ export class ChangesetHandler {
|
|||
*/
|
||||
private async UploadChange(
|
||||
changesetId: number,
|
||||
changesetXML: string,
|
||||
changesetXML: string
|
||||
): Promise<Map<string, string>> {
|
||||
const response = await this.osmConnection.post<XMLDocument>(
|
||||
"changeset/" + changesetId + "/upload",
|
||||
changesetXML,
|
||||
{ "Content-Type": "text/xml" },
|
||||
{ "Content-Type": "text/xml" }
|
||||
)
|
||||
const changes = this.parseUploadChangesetResponse(response)
|
||||
console.log("Uploaded changeset ", changesetId)
|
||||
|
|
|
|||
|
|
@ -10,44 +10,43 @@ import { AndroidPolyfill } from "../Web/AndroidPolyfill"
|
|||
import { QueryParameters } from "../Web/QueryParameters"
|
||||
|
||||
interface OsmUserInfo {
|
||||
|
||||
"id": number,
|
||||
"display_name": string,
|
||||
"account_created": string,
|
||||
"description": string,
|
||||
"contributor_terms": {
|
||||
"agreed": boolean,
|
||||
"pd": boolean
|
||||
id: number
|
||||
display_name: string
|
||||
account_created: string
|
||||
description: string
|
||||
contributor_terms: {
|
||||
agreed: boolean
|
||||
pd: boolean
|
||||
}
|
||||
"img"?: {
|
||||
"href": string,
|
||||
img?: {
|
||||
href: string
|
||||
}
|
||||
"roles": string[]
|
||||
"changesets": {
|
||||
"count": number
|
||||
roles: string[]
|
||||
changesets: {
|
||||
count: number
|
||||
}
|
||||
traces: {
|
||||
count: number
|
||||
}
|
||||
"blocks": {
|
||||
"received": {
|
||||
"count": number,
|
||||
"active": number
|
||||
blocks: {
|
||||
received: {
|
||||
count: number
|
||||
active: number
|
||||
}
|
||||
}
|
||||
home?: {
|
||||
lat: number,
|
||||
lon: number,
|
||||
lat: number
|
||||
lon: number
|
||||
zoom: number
|
||||
}
|
||||
"languages": string[]
|
||||
"messages": {
|
||||
"received": {
|
||||
"count": number,
|
||||
"unread": number
|
||||
},
|
||||
"sent": {
|
||||
"count": number
|
||||
languages: string[]
|
||||
messages: {
|
||||
received: {
|
||||
count: number
|
||||
unread: number
|
||||
}
|
||||
sent: {
|
||||
count: number
|
||||
}
|
||||
|
||||
id: number
|
||||
|
|
@ -60,12 +59,10 @@ interface OsmUserInfo {
|
|||
traces: { count: number }
|
||||
blocks: { received: { count: number; active: number } }
|
||||
img?: { href: string }
|
||||
home: { lat: number, lon: number }
|
||||
home: { lat: number; lon: number }
|
||||
languages?: string[]
|
||||
messages: { received: { count: number, unread: number }, sent: { count: number } }
|
||||
|
||||
}
|
||||
|
||||
messages: { received: { count: number; unread: number }; sent: { count: number } }
|
||||
}
|
||||
}
|
||||
|
||||
export default interface UserDetails {
|
||||
|
|
@ -81,7 +78,6 @@ export default interface UserDetails {
|
|||
tracesCount: number
|
||||
description?: string
|
||||
languages: string[]
|
||||
|
||||
}
|
||||
export type OsmServiceState = "online" | "readonly" | "offline" | "unknown" | "unreachable"
|
||||
|
||||
|
|
@ -126,14 +122,14 @@ export class OsmConnection {
|
|||
public userDetails: UIEventSource<UserDetails | undefined>
|
||||
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
|
||||
|
|
@ -193,7 +189,7 @@ export class OsmConnection {
|
|||
(user) =>
|
||||
!!user &&
|
||||
(this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"),
|
||||
[this.apiIsOnline],
|
||||
[this.apiIsOnline]
|
||||
)
|
||||
|
||||
this._dryRun = options.dryRun ?? new UIEventSource<boolean>(false)
|
||||
|
|
@ -232,7 +228,7 @@ 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)
|
||||
|
|
@ -241,7 +237,7 @@ export class OsmConnection {
|
|||
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)
|
||||
}
|
||||
|
|
@ -275,7 +271,7 @@ export class OsmConnection {
|
|||
}
|
||||
this.updateAuthObject(true)
|
||||
LocalStorageSource.get("location_before_login").setData(
|
||||
Utils.runningFromConsole ? undefined : window.location.href,
|
||||
Utils.runningFromConsole ? undefined : window.location.href
|
||||
)
|
||||
|
||||
this.auth.authenticate((err) => {
|
||||
|
|
@ -292,11 +288,13 @@ export class OsmConnection {
|
|||
this.loadingStatus.setData("error")
|
||||
return
|
||||
}
|
||||
const data = <{
|
||||
"version": "0.6",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"user": OsmUserInfo
|
||||
}>JSON.parse(result)
|
||||
const data = <
|
||||
{
|
||||
version: "0.6"
|
||||
license: "http://opendatacommons.org/licenses/odbl/1-0/"
|
||||
user: OsmUserInfo
|
||||
}
|
||||
>JSON.parse(result)
|
||||
const user = data.user
|
||||
const userdetails: UserDetails = {
|
||||
uid: user.id,
|
||||
|
|
@ -343,7 +341,7 @@ export class OsmConnection {
|
|||
method: "GET" | "POST" | "PUT" | "DELETE" = "GET",
|
||||
header?: Record<string, string>,
|
||||
content?: string,
|
||||
allowAnonymous: boolean = false,
|
||||
allowAnonymous: boolean = false
|
||||
): Promise<string> {
|
||||
const connection: osmAuth = this.auth
|
||||
if (allowAnonymous && !this.auth.authenticated()) {
|
||||
|
|
@ -351,7 +349,7 @@ export class OsmConnection {
|
|||
`${this.Backend()}/api/0.6/${path}`,
|
||||
header,
|
||||
method,
|
||||
content,
|
||||
content
|
||||
)
|
||||
if (possibleResult["content"]) {
|
||||
return possibleResult["content"]
|
||||
|
|
@ -371,15 +369,15 @@ 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 {
|
||||
ok(response)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -388,7 +386,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)
|
||||
}
|
||||
|
|
@ -396,7 +394,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)
|
||||
}
|
||||
|
|
@ -404,7 +402,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)
|
||||
}
|
||||
|
|
@ -443,7 +441,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
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -453,9 +451,9 @@ 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,
|
||||
true
|
||||
)
|
||||
const parsed = JSON.parse(response)
|
||||
console.log("Got result:", parsed)
|
||||
|
|
@ -482,14 +480,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
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -498,7 +496,7 @@ export class OsmConnection {
|
|||
file: gpx,
|
||||
description: options.description,
|
||||
tags: options.labels?.join(",") ?? "",
|
||||
visibility: options.visibility
|
||||
visibility: options.visibility,
|
||||
}
|
||||
|
||||
if (!contents.description) {
|
||||
|
|
@ -506,9 +504,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"
|
||||
|
|
@ -516,7 +514,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]
|
||||
}
|
||||
|
|
@ -527,7 +525,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)
|
||||
|
|
@ -548,15 +546,15 @@ 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 {
|
||||
ok()
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -576,15 +574,18 @@ export class OsmConnection {
|
|||
public getToken(): string {
|
||||
// https://www.openstreetmap.orgoauth2_access_token
|
||||
let prefix = this.Backend()
|
||||
while(prefix.endsWith("/")){
|
||||
prefix = prefix.substring(0, prefix.length-2)
|
||||
while (prefix.endsWith("/")) {
|
||||
prefix = prefix.substring(0, prefix.length - 2)
|
||||
}
|
||||
return QueryParameters.GetQueryParameter(prefix+ "oauth_token", undefined).data ?? window.localStorage.getItem(this._oauth_config.url + "oauth2_access_token")
|
||||
return (
|
||||
QueryParameters.GetQueryParameter(prefix + "oauth_token", undefined).data ??
|
||||
window.localStorage.getItem(this._oauth_config.url + "oauth2_access_token")
|
||||
)
|
||||
}
|
||||
|
||||
private async loginAndroidPolyfill() {
|
||||
const key = "https://www.openstreetmap.orgoauth2_access_token"
|
||||
if(localStorage.getItem(key)){
|
||||
if (localStorage.getItem(key)) {
|
||||
// We are probably already logged in
|
||||
return
|
||||
}
|
||||
|
|
@ -595,7 +596,6 @@ export class OsmConnection {
|
|||
console.log("Logged in!")
|
||||
}
|
||||
await this.loadUserInfo()
|
||||
|
||||
}
|
||||
private updateAuthObject(autoLogin: boolean) {
|
||||
let redirect_uri = Utils.runningFromConsole
|
||||
|
|
@ -614,7 +614,7 @@ export class OsmConnection {
|
|||
*/
|
||||
singlepage: !this._iframeMode && !AndroidPolyfill.inAndroid.data,
|
||||
auto: autoLogin,
|
||||
apiUrl: this._oauth_config.api_url ?? this._oauth_config.url
|
||||
apiUrl: this._oauth_config.api_url ?? this._oauth_config.url,
|
||||
})
|
||||
if (AndroidPolyfill.inAndroid.data) {
|
||||
this.loginAndroidPolyfill() // NO AWAIT!
|
||||
|
|
@ -658,7 +658,8 @@ export class OsmConnection {
|
|||
if (this.fakeUser) {
|
||||
return
|
||||
}
|
||||
this.fetchCapabilities().then(({ api, gpx }) => {
|
||||
this.fetchCapabilities()
|
||||
.then(({ api, gpx }) => {
|
||||
this.apiIsOnline.setData(api)
|
||||
this.gpxServiceIsOnline.setData(gpx)
|
||||
})
|
||||
|
|
@ -695,7 +696,7 @@ export class OsmConnection {
|
|||
}
|
||||
try {
|
||||
const result = await Utils.downloadJson<CapabilityResult>(
|
||||
this.Backend() + "/api/0.6/capabilities.json",
|
||||
this.Backend() + "/api/0.6/capabilities.json"
|
||||
)
|
||||
if (result?.api?.status === undefined) {
|
||||
console.log("Something went wrong:", result)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
import GeocodingProvider, { GeocodeResult, GeocodingOptions, SearchResult } from "./GeocodingProvider"
|
||||
import GeocodingProvider, {
|
||||
GeocodeResult,
|
||||
GeocodingOptions,
|
||||
SearchResult,
|
||||
} from "./GeocodingProvider"
|
||||
import { Utils } from "../../Utils"
|
||||
import { Store, Stores } from "../UIEventSource"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import GeocodingProvider, {
|
|||
GeocodingOptions,
|
||||
GeocodingUtils,
|
||||
ReverseGeocodingProvider,
|
||||
ReverseGeocodingResult
|
||||
ReverseGeocodingResult,
|
||||
} from "./GeocodingProvider"
|
||||
import { Utils } from "../../Utils"
|
||||
import { Feature, FeatureCollection } from "geojson"
|
||||
|
|
|
|||
|
|
@ -83,7 +83,10 @@ export default class ThemeSearch {
|
|||
}
|
||||
|
||||
let linkPrefix = `${path}/${layout.id.toLowerCase()}.html?`
|
||||
if ((location.hostname === "localhost" && !AndroidPolyfill.inAndroid.data) || location.hostname === "127.0.0.1") {
|
||||
if (
|
||||
(location.hostname === "localhost" && !AndroidPolyfill.inAndroid.data) ||
|
||||
location.hostname === "127.0.0.1"
|
||||
) {
|
||||
linkPrefix = `${path}/theme.html?layout=${layout.id}&`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ export class ReferencingWaysMetaTagger extends SimpleMetaTagger {
|
|||
super({
|
||||
keys: ["_referencing_ways"],
|
||||
isLazy: true,
|
||||
doc: "_referencing_ways contains - for a node - which ways use this node as point in their geometry. "
|
||||
doc: "_referencing_ways contains - for a node - which ways use this node as point in their geometry. ",
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ class CountryTagger extends SimpleMetaTagger {
|
|||
super({
|
||||
keys: ["_country"],
|
||||
doc: "The country codes of the of the country/countries that the feature is located in (with latlon2country). Might contain _multiple_ countries, separated by a `;`",
|
||||
includesDates: false
|
||||
includesDates: false,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -213,9 +213,9 @@ class RewriteMetaInfoTags extends SimpleMetaTagger {
|
|||
"_last_edit:changeset",
|
||||
"_last_edit:timestamp",
|
||||
"_version_number",
|
||||
"_backend"
|
||||
"_backend",
|
||||
],
|
||||
doc: "Information about the last edit of this object. This object will actually _rewrite_ some tags for features coming from overpass"
|
||||
doc: "Information about the last edit of this object. This object will actually _rewrite_ some tags for features coming from overpass",
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -246,16 +246,20 @@ class RewriteMetaInfoTags extends SimpleMetaTagger {
|
|||
|
||||
class NormalizePanoramax extends SimpleMetaTagger {
|
||||
constructor() {
|
||||
super(
|
||||
{
|
||||
keys: ["panoramax"],
|
||||
doc: "Converts a `panoramax=hash1;hash2;hash3;...` into `panoramax=hash1`,`panoramax:0=hash1`...",
|
||||
isLazy: false,
|
||||
cleanupRetagger: true
|
||||
})
|
||||
super({
|
||||
keys: ["panoramax"],
|
||||
doc: "Converts a `panoramax=hash1;hash2;hash3;...` into `panoramax=hash1`,`panoramax:0=hash1`...",
|
||||
isLazy: false,
|
||||
cleanupRetagger: true,
|
||||
})
|
||||
}
|
||||
|
||||
private addValue(comesFromKey: string, tags: Record<string, string>, hashesToAdd: string[], postfix?: string) {
|
||||
private addValue(
|
||||
comesFromKey: string,
|
||||
tags: Record<string, string>,
|
||||
hashesToAdd: string[],
|
||||
postfix?: string
|
||||
) {
|
||||
let basekey = "panoramax"
|
||||
if (postfix) {
|
||||
basekey = "panoramax:" + postfix
|
||||
|
|
@ -279,7 +283,11 @@ class NormalizePanoramax extends SimpleMetaTagger {
|
|||
* new NormalizePanoramax().applyMetaTagsOnFeature(_, _, tags, _)
|
||||
* tags.data // => {"panoramax": "abc", "panoramax:0" : "def", "panoramax:1": "ghi", "panoramax:2":"xyz", "panoramax:3":"uvw", "panoramax:streetsign":"a", "panoramax:streetsign:0":"b","panoramax:streetsign:1": "c"}
|
||||
*/
|
||||
applyMetaTagsOnFeature(feature: Feature, layer: LayerConfig, tags: UIEventSource<Record<string, string>>): boolean {
|
||||
applyMetaTagsOnFeature(
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
tags: UIEventSource<Record<string, string>>
|
||||
): boolean {
|
||||
const tgs = tags.data
|
||||
let somethingChanged = false
|
||||
for (const key in tgs) {
|
||||
|
|
@ -295,7 +303,6 @@ class NormalizePanoramax extends SimpleMetaTagger {
|
|||
this.addValue(key, tgs, parts)
|
||||
somethingChanged = true
|
||||
} else {
|
||||
|
||||
const postfix = key.match(/panoramax:([^:]+)(:[0-9]+)?/)?.[1]
|
||||
if (postfix) {
|
||||
this.addValue(key, tgs, parts, postfix)
|
||||
|
|
@ -316,7 +323,7 @@ export default class SimpleMetaTaggers {
|
|||
public static geometryType = new InlineMetaTagger(
|
||||
{
|
||||
keys: ["_geometry:type"],
|
||||
doc: "Adds the geometry type as property. This is identical to the GoeJson geometry type and is one of `Point`,`LineString`, `Polygon` and exceptionally `MultiPolygon` or `MultiLineString`"
|
||||
doc: "Adds the geometry type as property. This is identical to the GoeJson geometry type and is one of `Point`,`LineString`, `Polygon` and exceptionally `MultiPolygon` or `MultiLineString`",
|
||||
},
|
||||
(feature) => {
|
||||
const changed = feature.properties["_geometry:type"] === feature.geometry.type
|
||||
|
|
@ -342,12 +349,12 @@ export default class SimpleMetaTaggers {
|
|||
W: 270,
|
||||
WNW: 292.5,
|
||||
NW: 315,
|
||||
NNW: 337.5
|
||||
NNW: 337.5,
|
||||
}
|
||||
private static latlon = new InlineMetaTagger(
|
||||
{
|
||||
keys: ["_lat", "_lon"],
|
||||
doc: "The latitude and longitude of the point (or centerpoint in the case of a way/area)"
|
||||
doc: "The latitude and longitude of the point (or centerpoint in the case of a way/area)",
|
||||
},
|
||||
(feature) => {
|
||||
const centerPoint = GeoOperations.centerpoint(feature)
|
||||
|
|
@ -362,7 +369,7 @@ export default class SimpleMetaTaggers {
|
|||
{
|
||||
doc: "The layer-id to which this feature belongs. Note that this might be return any applicable if `passAllFeatures` is defined.",
|
||||
keys: ["_layer"],
|
||||
includesDates: false
|
||||
includesDates: false,
|
||||
},
|
||||
(feature, layer) => {
|
||||
if (feature.properties._layer === layer.id) {
|
||||
|
|
@ -378,11 +385,11 @@ export default class SimpleMetaTaggers {
|
|||
"sidewalk:left",
|
||||
"sidewalk:right",
|
||||
"generic_key:left:property",
|
||||
"generic_key:right:property"
|
||||
"generic_key:right:property",
|
||||
],
|
||||
doc: "Rewrites tags from 'generic_key:both:property' as 'generic_key:left:property' and 'generic_key:right:property' (and similar for sidewalk tagging). Note that this rewritten tags _will be reuploaded on a change_. To prevent to much unrelated retagging, this is only enabled if the layer has at least some lineRenderings with offset defined",
|
||||
includesDates: false,
|
||||
cleanupRetagger: true
|
||||
cleanupRetagger: true,
|
||||
},
|
||||
(feature, layer) => {
|
||||
if (!layer.lineRendering.some((lr) => lr.leftRightSensitive)) {
|
||||
|
|
@ -396,7 +403,7 @@ export default class SimpleMetaTaggers {
|
|||
{
|
||||
keys: ["_surface"],
|
||||
doc: "The surface area of the feature in square meters. Not set on points and ways",
|
||||
isLazy: true
|
||||
isLazy: true,
|
||||
},
|
||||
(feature) => {
|
||||
if (feature.geometry.type !== "Polygon" && feature.geometry.type !== "MultiPolygon") {
|
||||
|
|
@ -414,7 +421,7 @@ export default class SimpleMetaTaggers {
|
|||
{
|
||||
keys: ["_surface:ha"],
|
||||
doc: "The surface area of the feature in hectare. Not set on points and ways",
|
||||
isLazy: true
|
||||
isLazy: true,
|
||||
},
|
||||
(feature) => {
|
||||
if (feature.geometry.type !== "Polygon" && feature.geometry.type !== "MultiPolygon") {
|
||||
|
|
@ -432,7 +439,7 @@ export default class SimpleMetaTaggers {
|
|||
private static levels = new InlineMetaTagger(
|
||||
{
|
||||
doc: "Extract the 'level'-tag into a normalized, ';'-separated value called '_level' (which also includes 'repeat_on'). The `level` tag (without underscore) will be normalized with only the value of `level`.",
|
||||
keys: ["_level"]
|
||||
keys: ["_level"],
|
||||
},
|
||||
(feature) => {
|
||||
let somethingChanged = false
|
||||
|
|
@ -467,7 +474,7 @@ export default class SimpleMetaTaggers {
|
|||
private static canonicalize = new InlineMetaTagger(
|
||||
{
|
||||
doc: "If 'units' is defined in the layoutConfig, then this metatagger will rewrite the specified keys to have the canonical form (e.g. `1meter` will be rewritten to `1m`; `1` will be rewritten to `1m` as well)",
|
||||
keys: ["Theme-defined keys"]
|
||||
keys: ["Theme-defined keys"],
|
||||
},
|
||||
(feature, _, __, state) => {
|
||||
const units = Utils.NoNull(
|
||||
|
|
@ -524,7 +531,7 @@ export default class SimpleMetaTaggers {
|
|||
private static lngth = new InlineMetaTagger(
|
||||
{
|
||||
keys: ["_length", "_length:km"],
|
||||
doc: "The total length of a feature in meters (and in kilometers, rounded to one decimal for '_length:km'). For a surface, the length of the perimeter"
|
||||
doc: "The total length of a feature in meters (and in kilometers, rounded to one decimal for '_length:km'). For a surface, the length of the perimeter",
|
||||
},
|
||||
(feature) => {
|
||||
const l = GeoOperations.lengthInMeters(feature)
|
||||
|
|
@ -540,7 +547,7 @@ export default class SimpleMetaTaggers {
|
|||
keys: ["_isOpen"],
|
||||
doc: "If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no')",
|
||||
includesDates: true,
|
||||
isLazy: true
|
||||
isLazy: true,
|
||||
},
|
||||
(feature) => {
|
||||
if (Utils.runningFromConsole) {
|
||||
|
|
@ -579,8 +586,8 @@ export default class SimpleMetaTaggers {
|
|||
lon: lon,
|
||||
address: {
|
||||
country_code: tags._country.toLowerCase(),
|
||||
state: undefined
|
||||
}
|
||||
state: undefined,
|
||||
},
|
||||
},
|
||||
<any>{ tag_key: "opening_hours" }
|
||||
)
|
||||
|
|
@ -592,14 +599,14 @@ export default class SimpleMetaTaggers {
|
|||
delete tags._isOpen
|
||||
tags["_isOpen"] = "parse_error"
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
)
|
||||
private static directionSimplified = new InlineMetaTagger(
|
||||
{
|
||||
keys: ["_direction:numerical", "_direction:leftright"],
|
||||
doc: "_direction:numerical is a normalized, numerical direction based on 'camera:direction' or on 'direction'; it is only present if a valid direction is found (e.g. 38.5 or NE). _direction:leftright is either 'left' or 'right', which is left-looking on the map or 'right-looking' on the map"
|
||||
doc: "_direction:numerical is a normalized, numerical direction based on 'camera:direction' or on 'direction'; it is only present if a valid direction is found (e.g. 38.5 or NE). _direction:leftright is either 'left' or 'right', which is left-looking on the map or 'right-looking' on the map",
|
||||
},
|
||||
(feature) => {
|
||||
const tags = feature.properties
|
||||
|
|
@ -624,7 +631,7 @@ export default class SimpleMetaTaggers {
|
|||
{
|
||||
keys: ["_direction:centerpoint"],
|
||||
isLazy: true,
|
||||
doc: "_direction:centerpoint is the direction of the linestring (in degrees) if one were standing at the projected centerpoint."
|
||||
doc: "_direction:centerpoint is the direction of the linestring (in degrees) if one were standing at the projected centerpoint.",
|
||||
},
|
||||
(feature: Feature) => {
|
||||
if (feature.geometry.type !== "LineString") {
|
||||
|
|
@ -647,7 +654,7 @@ export default class SimpleMetaTaggers {
|
|||
delete feature.properties["_direction:centerpoint"]
|
||||
feature.properties["_direction:centerpoint"] = bearing
|
||||
return bearing
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return true
|
||||
|
|
@ -657,7 +664,7 @@ export default class SimpleMetaTaggers {
|
|||
{
|
||||
keys: ["_now:date", "_now:datetime"],
|
||||
doc: "Adds the time that the data got loaded - pretty much the time of downloading from overpass. The format is YYYY-MM-DD hh:mm, aka 'sortable' aka ISO-8601-but-not-entirely",
|
||||
includesDates: true
|
||||
includesDates: true,
|
||||
},
|
||||
(feature) => {
|
||||
const now = new Date()
|
||||
|
|
@ -681,7 +688,7 @@ export default class SimpleMetaTaggers {
|
|||
keys: ["_last_edit:passed_time"],
|
||||
doc: "Gives the number of seconds since the last edit. Note that this will _not_ update, but rather be the number of seconds elapsed at the moment this tag is read first",
|
||||
isLazy: true,
|
||||
includesDates: true
|
||||
includesDates: true,
|
||||
},
|
||||
(feature) => {
|
||||
Utils.AddLazyProperty(feature.properties, "_last_edit:passed_time", () => {
|
||||
|
|
@ -700,7 +707,7 @@ export default class SimpleMetaTaggers {
|
|||
{
|
||||
keys: ["_currency"],
|
||||
doc: "Adds the currency valid for the object, based on country or explicit tagging. Can be a single currency or a semicolon-separated list of currencies. Empty if no currency is found.",
|
||||
isLazy: true
|
||||
isLazy: true,
|
||||
},
|
||||
(feature: Feature, layer: LayerConfig, tagsStore: UIEventSource<OsmTags>) => {
|
||||
if (tagsStore === undefined) {
|
||||
|
|
@ -742,7 +749,6 @@ export default class SimpleMetaTaggers {
|
|||
}
|
||||
)
|
||||
|
||||
|
||||
public static metatags: SimpleMetaTagger[] = [
|
||||
SimpleMetaTaggers.latlon,
|
||||
SimpleMetaTaggers.layerInfo,
|
||||
|
|
@ -762,7 +768,7 @@ export default class SimpleMetaTaggers {
|
|||
SimpleMetaTaggers.referencingWays,
|
||||
SimpleMetaTaggers.timeSinceLastEdit,
|
||||
SimpleMetaTaggers.currency,
|
||||
SimpleMetaTaggers.normalizePanoramax
|
||||
SimpleMetaTaggers.normalizePanoramax,
|
||||
]
|
||||
|
||||
/**
|
||||
|
|
@ -844,8 +850,8 @@ export default class SimpleMetaTaggers {
|
|||
[
|
||||
"Metatags are extra tags available, in order to display more data or to give better questions.",
|
||||
"They are calculated automatically on every feature when the data arrives in the webbrowser. This document gives an overview of the available metatags.",
|
||||
"**Hint:** when using metatags, add the [query parameter](URL_Parameters.md) `debug=true` to the URL. This will include a box in the popup for features which shows all the properties of the object"
|
||||
].join("\n")
|
||||
"**Hint:** when using metatags, add the [query parameter](URL_Parameters.md) `debug=true` to the URL. This will include a box in the popup for features which shows all the properties of the object",
|
||||
].join("\n"),
|
||||
]
|
||||
|
||||
subElements.push("## Metatags calculated by MapComplete")
|
||||
|
|
|
|||
|
|
@ -182,7 +182,9 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
|
||||
let testingDefaultValue = false
|
||||
if (
|
||||
!Constants.osmAuthConfig.url.startsWith("https://master.apis.dev.openstreetmap.org") && !Utils.runningFromConsole && location.hostname === "127.0.0.1"
|
||||
!Constants.osmAuthConfig.url.startsWith("https://master.apis.dev.openstreetmap.org") &&
|
||||
!Utils.runningFromConsole &&
|
||||
location.hostname === "127.0.0.1"
|
||||
) {
|
||||
testingDefaultValue = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export class GeoLocationState {
|
|||
* 'denied' means that we don't have access
|
||||
*/
|
||||
public readonly permission: UIEventSource<GeolocationPermissionState> = new UIEventSource(
|
||||
"prompt",
|
||||
"prompt"
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
@ -130,7 +130,7 @@ export class GeoLocationState {
|
|||
}
|
||||
return Translations.t.general.waitingForLocation
|
||||
},
|
||||
[this.allowMoving, this.permission, this.currentGPSLocation],
|
||||
[this.allowMoving, this.permission, this.currentGPSLocation]
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -165,15 +165,15 @@ export class GeoLocationState {
|
|||
return
|
||||
}
|
||||
|
||||
if(AndroidPolyfill.inAndroid.data){
|
||||
if (AndroidPolyfill.inAndroid.data) {
|
||||
this.permission.setData("requested")
|
||||
this.permission.addCallbackAndRunD(p => {
|
||||
if(p === "granted"){
|
||||
this.permission.addCallbackAndRunD((p) => {
|
||||
if (p === "granted") {
|
||||
this.startWatching()
|
||||
return true
|
||||
}
|
||||
})
|
||||
AndroidPolyfill.requestGeoPermission().then(state => {
|
||||
AndroidPolyfill.requestGeoPermission().then((state) => {
|
||||
const granted = state.value === "true"
|
||||
this.permission.set(granted ? "granted" : "denied")
|
||||
})
|
||||
|
|
@ -218,15 +218,14 @@ export class GeoLocationState {
|
|||
* @private
|
||||
*/
|
||||
private async startWatching() {
|
||||
|
||||
if(AndroidPolyfill.inAndroid.data){
|
||||
AndroidPolyfill.watchLocation( this.currentGPSLocation, location => {
|
||||
if (AndroidPolyfill.inAndroid.data) {
|
||||
AndroidPolyfill.watchLocation(this.currentGPSLocation, (location) => {
|
||||
console.log(JSON.stringify(location))
|
||||
})
|
||||
}
|
||||
|
||||
navigator.geolocation.watchPosition(
|
||||
(position: GeolocationPosition) => {
|
||||
(position: GeolocationPosition) => {
|
||||
this._gpsAvailable.set(true)
|
||||
this.currentGPSLocation.setData(position.coords)
|
||||
this._previousLocationGrant.setData(true)
|
||||
|
|
@ -249,5 +248,4 @@ export class GeoLocationState {
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -350,7 +350,9 @@ export default class UserRelatedState {
|
|||
* List of all hidden themes that have been seen before
|
||||
* @param osmConnection
|
||||
*/
|
||||
public static initDiscoveredHiddenThemes(osmConnection: OsmConnection): Store<undefined | string[]> {
|
||||
public static initDiscoveredHiddenThemes(
|
||||
osmConnection: OsmConnection
|
||||
): Store<undefined | string[]> {
|
||||
const prefix = "mapcomplete-hidden-theme-"
|
||||
const userPreferences = osmConnection.preferencesHandler.allPreferences
|
||||
return userPreferences.mapD((preferences) =>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,42 @@
|
|||
import { Utils } from "../../Utils"
|
||||
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
|
||||
export class ThemeMetaTagging {
|
||||
public static readonly themeName = "usersettings"
|
||||
public static readonly themeName = "usersettings"
|
||||
|
||||
public metaTaggging_for_usersettings(feat: {properties: Record<string, string>}) {
|
||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
|
||||
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/</g,'<')?.replace(/>/g,'>') ?? '' )
|
||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
|
||||
Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
|
||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
|
||||
feat.properties['__current_backgroun'] = 'initial_value'
|
||||
}
|
||||
}
|
||||
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
|
||||
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
|
||||
feat.properties._description
|
||||
.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
|
||||
?.at(1)
|
||||
)
|
||||
Utils.AddLazyProperty(
|
||||
feat.properties,
|
||||
"_d",
|
||||
() => feat.properties._description?.replace(/</g, "<")?.replace(/>/g, ">") ?? ""
|
||||
)
|
||||
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () =>
|
||||
((feat) => {
|
||||
const e = document.createElement("div")
|
||||
e.innerHTML = feat.properties._d
|
||||
return Array.from(e.getElementsByTagName("a")).filter(
|
||||
(a) => a.href.match(/mastodon|en.osm.town/) !== null
|
||||
)[0]?.href
|
||||
})(feat)
|
||||
)
|
||||
Utils.AddLazyProperty(feat.properties, "_mastodon_link", () =>
|
||||
((feat) => {
|
||||
const e = document.createElement("div")
|
||||
e.innerHTML = feat.properties._d
|
||||
return Array.from(e.getElementsByTagName("a")).filter(
|
||||
(a) => a.getAttribute("rel")?.indexOf("me") >= 0
|
||||
)[0]?.href
|
||||
})(feat)
|
||||
)
|
||||
Utils.AddLazyProperty(
|
||||
feat.properties,
|
||||
"_mastodon_candidate",
|
||||
() => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a
|
||||
)
|
||||
feat.properties["__current_backgroun"] = "initial_value"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ import { Store, UIEventSource } from "../UIEventSource"
|
|||
import { OsmConnection } from "../Osm/OsmConnection"
|
||||
|
||||
export interface DatabridgePlugin {
|
||||
request<T extends (string | object) = string | object>(options: { key: string }): Promise<{ value: T }>;
|
||||
request<T extends string | object = string | object>(options: {
|
||||
key: string
|
||||
}): Promise<{ value: T }>
|
||||
}
|
||||
|
||||
const DatabridgePluginSingleton = registerPlugin<DatabridgePlugin>("Databridge", {
|
||||
|
|
@ -28,17 +30,25 @@ export class AndroidPolyfill {
|
|||
private static readonly databridgePlugin: DatabridgePlugin = DatabridgePluginSingleton
|
||||
private static readonly _inAndroid: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
public static readonly inAndroid: Store<boolean> = AndroidPolyfill._inAndroid
|
||||
private static readonly _geolocationPermission: UIEventSource<"granted" | "denied" | "prompt"> = new UIEventSource("prompt")
|
||||
public static readonly geolocationPermission: Store<"granted" | "denied" | "prompt"> = this._geolocationPermission
|
||||
private static readonly _geolocationPermission: UIEventSource<"granted" | "denied" | "prompt"> =
|
||||
new UIEventSource("prompt")
|
||||
public static readonly geolocationPermission: Store<"granted" | "denied" | "prompt"> =
|
||||
this._geolocationPermission
|
||||
|
||||
/**
|
||||
* Registers 'navigator.'
|
||||
* @private
|
||||
*/
|
||||
private static backfillGeolocation(databridgePlugin: DatabridgePlugin) {
|
||||
const src = UIEventSource.FromPromise(databridgePlugin.request({ key: "location:has-permission" }))
|
||||
src.addCallbackAndRunD(permission => {
|
||||
console.log("> Checking geopermission gave: ", JSON.stringify(permission), permission.value)
|
||||
const src = UIEventSource.FromPromise(
|
||||
databridgePlugin.request({ key: "location:has-permission" })
|
||||
)
|
||||
src.addCallbackAndRunD((permission) => {
|
||||
console.log(
|
||||
"> Checking geopermission gave: ",
|
||||
JSON.stringify(permission),
|
||||
permission.value
|
||||
)
|
||||
const granted = permission.value === "true"
|
||||
AndroidPolyfill._geolocationPermission.set(granted ? "granted" : "denied")
|
||||
})
|
||||
|
|
@ -61,17 +71,25 @@ export class AndroidPolyfill {
|
|||
}
|
||||
|
||||
public static async requestLoginCodes() {
|
||||
const result = await DatabridgePluginSingleton.request<{ oauth_token: string }>({ key: "request:login" })
|
||||
const result = await DatabridgePluginSingleton.request<{ oauth_token: string }>({
|
||||
key: "request:login",
|
||||
})
|
||||
const token: string = result.value.oauth_token
|
||||
console.log("AndroidPolyfill: received oauth_token; trying to pass them to the oauth lib", token)
|
||||
console.log(
|
||||
"AndroidPolyfill: received oauth_token; trying to pass them to the oauth lib",
|
||||
token
|
||||
)
|
||||
return token
|
||||
}
|
||||
|
||||
public static onBackButton(callback: () => boolean, options: {
|
||||
returnToIndex: Store<boolean>
|
||||
}) {
|
||||
public static onBackButton(
|
||||
callback: () => boolean,
|
||||
options: {
|
||||
returnToIndex: Store<boolean>
|
||||
}
|
||||
) {
|
||||
console.log("Registering back button callback", callback)
|
||||
DatabridgePluginSingleton.request({ key: "backbutton" }).then(ev => {
|
||||
DatabridgePluginSingleton.request({ key: "backbutton" }).then((ev) => {
|
||||
console.log("AndroidPolyfill: received backbutton: ", ev)
|
||||
if (ev === null) {
|
||||
// Probably in web environment
|
||||
|
|
@ -88,28 +106,38 @@ export class AndroidPolyfill {
|
|||
window.location.href = "/"
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
public static watchLocation(writeInto: UIEventSource<GeolocationCoordinates>, callback: (location) => void) {
|
||||
public static watchLocation(
|
||||
writeInto: UIEventSource<GeolocationCoordinates>,
|
||||
callback: (location) => void
|
||||
) {
|
||||
DatabridgePluginSingleton.request({
|
||||
key: "location:watch",
|
||||
}).then((l: {
|
||||
value: { latitude: number, longitude: number, accuraccy: number, altidude: number, heading: number, speed:number }
|
||||
}) => {
|
||||
// example l: {"value":{"latitude":51.0618627,"longitude":3.730468566666667,"accuracy":2.0393495559692383,"altitude":46.408,"heading":168.2969970703125}}
|
||||
console.log("Received location from Android:", JSON.stringify(l))
|
||||
const loc = l.value
|
||||
writeInto.set({
|
||||
latitude: loc.latitude,
|
||||
longitude: loc.longitude,
|
||||
heading: loc.heading,
|
||||
accuracy: loc.accuraccy,
|
||||
altitude: loc.altidude,
|
||||
altitudeAccuracy: undefined,
|
||||
speed: loc.speed,
|
||||
})
|
||||
})
|
||||
}).then(
|
||||
(l: {
|
||||
value: {
|
||||
latitude: number
|
||||
longitude: number
|
||||
accuraccy: number
|
||||
altidude: number
|
||||
heading: number
|
||||
speed: number
|
||||
}
|
||||
}) => {
|
||||
// example l: {"value":{"latitude":51.0618627,"longitude":3.730468566666667,"accuracy":2.0393495559692383,"altitude":46.408,"heading":168.2969970703125}}
|
||||
console.log("Received location from Android:", JSON.stringify(l))
|
||||
const loc = l.value
|
||||
writeInto.set({
|
||||
latitude: loc.latitude,
|
||||
longitude: loc.longitude,
|
||||
heading: loc.heading,
|
||||
accuracy: loc.accuraccy,
|
||||
altitude: loc.altidude,
|
||||
altitudeAccuracy: undefined,
|
||||
speed: loc.speed,
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,22 +2,21 @@
|
|||
* Various tools and types to work with the community index (https://openstreetmap.community/; https://github.com/osmlab/osm-community-index)
|
||||
*/
|
||||
|
||||
|
||||
export interface CommunityResource {
|
||||
/**
|
||||
* A unique identifier for the resource
|
||||
* "pattern": "^[-_.A-Za-z0-9]+$"
|
||||
*/
|
||||
id: string,
|
||||
id: string
|
||||
/**
|
||||
* Type of community resource (thus: platform)
|
||||
*/
|
||||
type: string,
|
||||
type: string
|
||||
/**
|
||||
* included and excluded locations for this item
|
||||
* See location-conflation documentation for compatible values: https://github.com/rapideditor/location-conflation#readme
|
||||
*/
|
||||
locationSet?,
|
||||
locationSet?
|
||||
|
||||
/** Array of ISO-639-1 (2 letter) or ISO-639-3 (3 letter) codes in lowercase
|
||||
* */
|
||||
|
|
@ -27,7 +26,5 @@ export interface CommunityResource {
|
|||
*/
|
||||
account?: string
|
||||
|
||||
resolved?: { url: string, name: string, description: string } & Record<string, string>
|
||||
|
||||
resolved?: { url: string; name: string; description: string } & Record<string, string>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ export default class ThemeViewStateHashActor {
|
|||
*
|
||||
*/
|
||||
constructor(state: {
|
||||
featureSwitches: {featureSwitchBackToThemeOverview: Store<boolean>}
|
||||
indexedFeatures: IndexedFeatureSource,
|
||||
selectedElement: UIEventSource<Feature>,
|
||||
guistate: MenuState,
|
||||
featureSwitches: { featureSwitchBackToThemeOverview: Store<boolean> }
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
selectedElement: UIEventSource<Feature>
|
||||
guistate: MenuState
|
||||
}) {
|
||||
this._state = state
|
||||
AndroidPolyfill.onBackButton(() => this.back(), {
|
||||
returnToIndex: state.featureSwitches.featureSwitchBackToThemeOverview
|
||||
returnToIndex: state.featureSwitches.featureSwitchBackToThemeOverview,
|
||||
})
|
||||
|
||||
const hashOnLoad = Hash.hash.data
|
||||
|
|
@ -81,7 +81,6 @@ export default class ThemeViewStateHashActor {
|
|||
|
||||
// When all is done, set the hash. This must happen last to give the code above correct info
|
||||
this.setHash()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue