forked from MapComplete/MapComplete
Chore: reformat all files with prettier
This commit is contained in:
parent
5757ae5dea
commit
d008dcb54d
214 changed files with 8926 additions and 8196 deletions
|
@ -1,6 +1,6 @@
|
|||
import {Store, UIEventSource} from "../UIEventSource"
|
||||
import {Utils} from "../../Utils"
|
||||
import {RasterLayerPolygon, RasterLayerUtils,} from "../../Models/RasterLayers"
|
||||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import { Utils } from "../../Utils"
|
||||
import { RasterLayerPolygon, RasterLayerUtils } from "../../Models/RasterLayers"
|
||||
|
||||
/**
|
||||
* When a user pans around on the map, they might pan out of the range of the current background raster layer.
|
||||
|
@ -35,7 +35,7 @@ export default class BackgroundLayerResetter {
|
|||
availableLayers,
|
||||
currentBgPolygon?.properties?.category
|
||||
)
|
||||
if(!availableInSameCat){
|
||||
if (!availableInSameCat) {
|
||||
return
|
||||
}
|
||||
console.log("Selecting a different layer:", availableInSameCat.properties.id)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import {QueryParameters} from "../Web/QueryParameters"
|
||||
import {BBox} from "../BBox"
|
||||
import { QueryParameters } from "../Web/QueryParameters"
|
||||
import { BBox } from "../BBox"
|
||||
import Constants from "../../Models/Constants"
|
||||
import {GeoLocationState} from "../State/GeoLocationState"
|
||||
import {UIEventSource} from "../UIEventSource"
|
||||
import {Feature, LineString, Point} from "geojson"
|
||||
import {FeatureSource, WritableFeatureSource} from "../FeatureSource/FeatureSource"
|
||||
import {LocalStorageSource} from "../Web/LocalStorageSource"
|
||||
import {GeoOperations} from "../GeoOperations"
|
||||
import {OsmTags} from "../../Models/OsmFeature"
|
||||
import { GeoLocationState } from "../State/GeoLocationState"
|
||||
import { UIEventSource } from "../UIEventSource"
|
||||
import { Feature, LineString, Point } from "geojson"
|
||||
import { FeatureSource, WritableFeatureSource } from "../FeatureSource/FeatureSource"
|
||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
import { GeoOperations } from "../GeoOperations"
|
||||
import { OsmTags } from "../../Models/OsmFeature"
|
||||
import StaticFeatureSource from "../FeatureSource/Sources/StaticFeatureSource"
|
||||
import {MapProperties} from "../../Models/MapProperties"
|
||||
import { MapProperties } from "../../Models/MapProperties"
|
||||
|
||||
/**
|
||||
* The geolocation-handler takes a map-location and a geolocation state.
|
||||
|
@ -39,7 +39,9 @@ export default class GeoLocationHandler {
|
|||
/**
|
||||
* The last moment that the map has moved
|
||||
*/
|
||||
public readonly mapHasMoved: UIEventSource<Date | undefined> = new UIEventSource<Date | undefined>(undefined)
|
||||
public readonly mapHasMoved: UIEventSource<Date | undefined> = new UIEventSource<
|
||||
Date | undefined
|
||||
>(undefined)
|
||||
private readonly selectedElement: UIEventSource<any>
|
||||
private readonly mapProperties?: MapProperties
|
||||
private readonly gpsLocationHistoryRetentionTime?: UIEventSource<number>
|
||||
|
@ -80,8 +82,11 @@ export default class GeoLocationHandler {
|
|||
// The map hasn't moved yet; we received our first coordinates, so let's move there!
|
||||
self.MoveMapToCurrentLocation()
|
||||
}
|
||||
if (timeSinceLastRequest < Constants.zoomToLocationTimeout &&
|
||||
(this.mapHasMoved.data === undefined || this.mapHasMoved.data.getTime() < geolocationState.requestMoment.data?.getTime() )
|
||||
if (
|
||||
timeSinceLastRequest < Constants.zoomToLocationTimeout &&
|
||||
(this.mapHasMoved.data === undefined ||
|
||||
this.mapHasMoved.data.getTime() <
|
||||
geolocationState.requestMoment.data?.getTime())
|
||||
) {
|
||||
// still within request time and the map hasn't moved since requesting to jump to the current location
|
||||
self.MoveMapToCurrentLocation()
|
||||
|
@ -154,8 +159,8 @@ export default class GeoLocationHandler {
|
|||
return
|
||||
}
|
||||
|
||||
const properties = {
|
||||
id: "gps-"+i,
|
||||
const properties = {
|
||||
id: "gps-" + i,
|
||||
"user:location": "yes",
|
||||
date: new Date().toISOString(),
|
||||
}
|
||||
|
@ -164,7 +169,7 @@ export default class GeoLocationHandler {
|
|||
for (const k in keysToCopy) {
|
||||
// For some weird reason, the 'Object.keys' method doesn't work for the 'location: GeolocationCoordinates'-object and will thus not copy all the properties when using {...location}
|
||||
// As such, they are copied here
|
||||
if(location[k]){
|
||||
if (location[k]) {
|
||||
properties[k] = location[k]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,14 +20,15 @@ import { FixImages } from "../Models/ThemeConfig/Conversion/FixImages"
|
|||
import Svg from "../Svg"
|
||||
import {
|
||||
DoesImageExist,
|
||||
PrevalidateTheme, ValidateTagRenderings,
|
||||
PrevalidateTheme,
|
||||
ValidateTagRenderings,
|
||||
ValidateThemeAndLayers,
|
||||
} from "../Models/ThemeConfig/Conversion/Validation"
|
||||
import {DesugaringContext, Each, On} from "../Models/ThemeConfig/Conversion/Conversion";
|
||||
import {PrepareLayer, RewriteSpecial} from "../Models/ThemeConfig/Conversion/PrepareLayer";
|
||||
import {AllSharedLayers} from "../Customizations/AllSharedLayers";
|
||||
import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson";
|
||||
import questions from "../assets/tagRenderings/questions.json";
|
||||
import { DesugaringContext, Each, On } from "../Models/ThemeConfig/Conversion/Conversion"
|
||||
import { PrepareLayer, RewriteSpecial } from "../Models/ThemeConfig/Conversion/PrepareLayer"
|
||||
import { AllSharedLayers } from "../Customizations/AllSharedLayers"
|
||||
import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||
import questions from "../assets/tagRenderings/questions.json"
|
||||
|
||||
export default class DetermineLayout {
|
||||
private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path))
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {GeoOperations} from "./GeoOperations"
|
||||
import { GeoOperations } from "./GeoOperations"
|
||||
import Combine from "../UI/Base/Combine"
|
||||
import BaseUIElement from "../UI/BaseUIElement"
|
||||
import List from "../UI/Base/List"
|
||||
import Title from "../UI/Base/Title"
|
||||
import {BBox} from "./BBox"
|
||||
import {Feature, Geometry, MultiPolygon, Polygon} from "geojson"
|
||||
import {GeoJSONFeature} from "maplibre-gl";
|
||||
import { BBox } from "./BBox"
|
||||
import { Feature, Geometry, MultiPolygon, Polygon } from "geojson"
|
||||
import { GeoJSONFeature } from "maplibre-gl"
|
||||
|
||||
export interface ExtraFuncParams {
|
||||
/**
|
||||
|
@ -13,7 +13,10 @@ export interface ExtraFuncParams {
|
|||
* Note that more features then requested can be given back.
|
||||
* Format: [ [ geojson, geojson, geojson, ... ], [geojson, ...], ...]
|
||||
*/
|
||||
getFeaturesWithin: (layerId: string, bbox: BBox) => Feature<Geometry, Record<string, string>>[][]
|
||||
getFeaturesWithin: (
|
||||
layerId: string,
|
||||
bbox: BBox
|
||||
) => Feature<Geometry, Record<string, string>>[][]
|
||||
getFeatureById: (id: string) => Feature<Geometry, Record<string, string>>
|
||||
}
|
||||
|
||||
|
@ -55,7 +58,6 @@ class EnclosingFunc implements ExtraFunction {
|
|||
}
|
||||
for (const otherFeatures of otherFeaturess) {
|
||||
for (const otherFeature of otherFeatures) {
|
||||
|
||||
if (seenIds.has(otherFeature.properties.id)) {
|
||||
continue
|
||||
}
|
||||
|
@ -72,7 +74,7 @@ class EnclosingFunc implements ExtraFunction {
|
|||
<Feature<Polygon | MultiPolygon, any>>otherFeature
|
||||
)
|
||||
) {
|
||||
result.push({feat: otherFeature})
|
||||
result.push({ feat: otherFeature })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,11 +160,14 @@ class IntersectionFunc implements ExtraFunction {
|
|||
}
|
||||
for (const otherFeatures of otherLayers) {
|
||||
for (const otherFeature of otherFeatures) {
|
||||
const intersections = GeoOperations.LineIntersections(feat, <Feature<any, Record<string, string>>>otherFeature)
|
||||
const intersections = GeoOperations.LineIntersections(
|
||||
feat,
|
||||
<Feature<any, Record<string, string>>>otherFeature
|
||||
)
|
||||
if (intersections.length === 0) {
|
||||
continue
|
||||
}
|
||||
result.push({feat: otherFeature, intersections})
|
||||
result.push({ feat: otherFeature, intersections })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,7 +259,14 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
const maxDistance = options?.maxDistance ?? 500
|
||||
const uniqueTag: string | undefined = options?.uniqueTag
|
||||
let allFeatures: Feature[][]
|
||||
console.log("Calculating closest", options?.maxFeatures, "features around", feature, "in layer", features)
|
||||
console.log(
|
||||
"Calculating closest",
|
||||
options?.maxFeatures,
|
||||
"features around",
|
||||
feature,
|
||||
"in layer",
|
||||
features
|
||||
)
|
||||
if (typeof features === "string") {
|
||||
const name = features
|
||||
const bbox = GeoOperations.bbox(
|
||||
|
@ -272,7 +284,6 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
let closestFeatures: { feat: any; distance: number }[] = []
|
||||
|
||||
for (const feats of allFeatures) {
|
||||
|
||||
for (const otherFeature of feats) {
|
||||
if (
|
||||
otherFeature === feature ||
|
||||
|
@ -333,7 +344,7 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
const uniqueTagsMatch =
|
||||
otherFeature.properties[uniqueTag] !== undefined &&
|
||||
closestFeature.feat.properties[uniqueTag] ===
|
||||
otherFeature.properties[uniqueTag]
|
||||
otherFeature.properties[uniqueTag]
|
||||
if (uniqueTagsMatch) {
|
||||
targetIndex = -1
|
||||
if (closestFeature.distance > distance) {
|
||||
|
@ -341,7 +352,7 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
// We want to see the tag `uniquetag=some_value` only once in the entire list (e.g. to prevent road segements of identical names to fill up the list of 'names of nearby roads')
|
||||
// AT this point, we have found a closer segment with the same, identical tag
|
||||
// so we replace directly
|
||||
closestFeatures[i] = {feat: otherFeature, distance: distance}
|
||||
closestFeatures[i] = { feat: otherFeature, distance: distance }
|
||||
}
|
||||
break
|
||||
}
|
||||
|
@ -468,7 +479,15 @@ export class ExtraFunctions {
|
|||
.SetClass("flex-col")
|
||||
.AsMarkdown()
|
||||
|
||||
static readonly types = ["distanceTo", "overlapWith", "enclosingFeatures", "intersectionsWith", "closest", "closestn", "get"] as const
|
||||
static readonly types = [
|
||||
"distanceTo",
|
||||
"overlapWith",
|
||||
"enclosingFeatures",
|
||||
"intersectionsWith",
|
||||
"closest",
|
||||
"closestn",
|
||||
"get",
|
||||
] as const
|
||||
private static readonly allFuncs = [
|
||||
new DistanceToFunc(),
|
||||
new OverlapFunc(),
|
||||
|
@ -479,8 +498,9 @@ export class ExtraFunctions {
|
|||
new GetParsed(),
|
||||
]
|
||||
|
||||
|
||||
public static constructHelpers(params: ExtraFuncParams): Record<ExtraFuncType, (feature: Feature) => Function> {
|
||||
public static constructHelpers(
|
||||
params: ExtraFuncParams
|
||||
): Record<ExtraFuncType, (feature: Feature) => Function> {
|
||||
const record: Record<string, (feature: GeoJSONFeature) => Function> = {}
|
||||
for (const f of ExtraFunctions.allFuncs) {
|
||||
if (this.types.indexOf(<any>f._name) < 0) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {FeatureSource} from "../FeatureSource"
|
||||
import {UIEventSource} from "../../UIEventSource"
|
||||
import { FeatureSource } from "../FeatureSource"
|
||||
import { UIEventSource } from "../../UIEventSource"
|
||||
|
||||
/**
|
||||
* Constructs a UIEventStore for the properties of every Feature, indexed by id
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {IdbLocalStorage} from "../../Web/IdbLocalStorage"
|
||||
import {UIEventSource} from "../../UIEventSource"
|
||||
import { IdbLocalStorage } from "../../Web/IdbLocalStorage"
|
||||
import { UIEventSource } from "../../UIEventSource"
|
||||
|
||||
/**
|
||||
* A class which allows to read/write a tile to local storage.
|
||||
|
@ -14,14 +14,18 @@ export default class TileLocalStorage<T> {
|
|||
private readonly _layername: string
|
||||
private readonly inUse = new UIEventSource(false)
|
||||
private readonly cachedSources: Record<number, UIEventSource<T> & { flush: () => void }> = {}
|
||||
private readonly _maxAgeSeconds: number;
|
||||
private readonly _maxAgeSeconds: number
|
||||
|
||||
private constructor(layername: string, maxAgeSeconds: number) {
|
||||
this._layername = layername
|
||||
this._maxAgeSeconds = maxAgeSeconds;
|
||||
this._maxAgeSeconds = maxAgeSeconds
|
||||
}
|
||||
|
||||
public static construct<T>(backend: string, layername: string, maxAgeS: number): TileLocalStorage<T> {
|
||||
public static construct<T>(
|
||||
backend: string,
|
||||
layername: string,
|
||||
maxAgeS: number
|
||||
): TileLocalStorage<T> {
|
||||
const key = backend + "_" + layername
|
||||
const cached = TileLocalStorage.perLayer[key]
|
||||
if (cached) {
|
||||
|
@ -59,7 +63,10 @@ export default class TileLocalStorage<T> {
|
|||
await this.inUse.AsPromise((inUse) => !inUse)
|
||||
this.inUse.setData(true)
|
||||
await IdbLocalStorage.SetDirectly(this._layername + "_" + tileIndex, data)
|
||||
await IdbLocalStorage.SetDirectly(this._layername + "_" + tileIndex + "_date", Date.now())
|
||||
await IdbLocalStorage.SetDirectly(
|
||||
this._layername + "_" + tileIndex + "_date",
|
||||
Date.now()
|
||||
)
|
||||
|
||||
this.inUse.setData(false)
|
||||
} catch (e) {
|
||||
|
@ -80,7 +87,9 @@ export default class TileLocalStorage<T> {
|
|||
if (!TileLocalStorage.useIndexedDb) {
|
||||
return undefined
|
||||
}
|
||||
const date = <any>await IdbLocalStorage.GetDirectly(this._layername + "_" + tileIndex + "_date")
|
||||
const date = <any>(
|
||||
await IdbLocalStorage.GetDirectly(this._layername + "_" + tileIndex + "_date")
|
||||
)
|
||||
const maxAge = this._maxAgeSeconds
|
||||
const timeDiff = Date.now() - date
|
||||
if (timeDiff >= maxAge) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {FeatureSource} from "./FeatureSource"
|
||||
import { FeatureSource } from "./FeatureSource"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import SimpleFeatureSource from "./Sources/SimpleFeatureSource"
|
||||
import {Feature} from "geojson"
|
||||
import {UIEventSource} from "../UIEventSource"
|
||||
import { Feature } from "geojson"
|
||||
import { UIEventSource } from "../UIEventSource"
|
||||
|
||||
/**
|
||||
* In some rare cases, some elements are shown on multiple layers (when 'passthrough' is enabled)
|
||||
|
@ -59,8 +59,11 @@ export default class PerLayerFeatureSourceSplitter<T extends FeatureSource = Fea
|
|||
let foundALayer = false
|
||||
for (let i = 0; i < layers.length; i++) {
|
||||
const layer = layers[i]
|
||||
if(!layer.layerDef?.source){
|
||||
console.error("PerLayerFeatureSourceSplitter got a layer without a source:", layer.layerDef.id)
|
||||
if (!layer.layerDef?.source) {
|
||||
console.error(
|
||||
"PerLayerFeatureSourceSplitter got a layer without a source:",
|
||||
layer.layerDef.id
|
||||
)
|
||||
continue
|
||||
}
|
||||
if (layer.layerDef.source.osmTags.matchesProperties(f.properties)) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import { UIEventSource } from "../../UIEventSource"
|
|||
import { FeatureSource, IndexedFeatureSource } from "../FeatureSource"
|
||||
import { ChangeDescription, ChangeDescriptionTools } from "../../Osm/Actions/ChangeDescription"
|
||||
import { Feature } from "geojson"
|
||||
import {Utils} from "../../../Utils";
|
||||
import { Utils } from "../../../Utils"
|
||||
|
||||
export default class ChangeGeometryApplicator implements FeatureSource {
|
||||
public readonly features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([])
|
||||
|
@ -70,7 +70,7 @@ export default class ChangeGeometryApplicator implements FeatureSource {
|
|||
// We only apply the last change as that one'll have the latest geometry
|
||||
const change = changesForFeature[changesForFeature.length - 1]
|
||||
copy.geometry = ChangeDescriptionTools.getGeojsonGeometry(change)
|
||||
if(Utils.SameObject(copy.geometry, feature.geometry)){
|
||||
if (Utils.SameObject(copy.geometry, feature.geometry)) {
|
||||
// No actual changes: pass along the original
|
||||
newFeatures.push(feature)
|
||||
continue
|
||||
|
|
|
@ -30,7 +30,7 @@ export default class FeatureSourceMerger implements IndexedFeatureSource {
|
|||
}
|
||||
|
||||
public addSource(source: FeatureSource) {
|
||||
if(!source){
|
||||
if (!source) {
|
||||
return
|
||||
}
|
||||
this._sources.push(source)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/**
|
||||
* Fetches a geojson file somewhere and passes it along
|
||||
*/
|
||||
import {Store, UIEventSource} from "../../UIEventSource"
|
||||
import {Utils} from "../../../Utils"
|
||||
import {FeatureSource} from "../FeatureSource"
|
||||
import {BBox} from "../../BBox"
|
||||
import {GeoOperations} from "../../GeoOperations"
|
||||
import {Feature} from "geojson"
|
||||
import { Store, UIEventSource } from "../../UIEventSource"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { FeatureSource } from "../FeatureSource"
|
||||
import { BBox } from "../../BBox"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
import { Feature } from "geojson"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import {Tiles} from "../../../Models/TileRange"
|
||||
import { Tiles } from "../../../Models/TileRange"
|
||||
|
||||
export default class GeoJsonSource implements FeatureSource {
|
||||
public readonly features: Store<Feature[]>
|
||||
|
@ -65,13 +65,13 @@ export default class GeoJsonSource implements FeatureSource {
|
|||
return
|
||||
}
|
||||
this.LoadJSONFrom(url, eventsource, layer)
|
||||
.then((fs) => console.debug("Loaded",fs.length, "features from", url))
|
||||
.then((fs) => console.debug("Loaded", fs.length, "features from", url))
|
||||
.catch((err) => console.warn("Could not load ", url, "due to", err))
|
||||
return true // data is loaded, we can safely unregister
|
||||
})
|
||||
} else {
|
||||
this.LoadJSONFrom(url, eventsource, layer)
|
||||
.then((fs) => console.debug("Loaded",fs.length, "features from", url))
|
||||
.then((fs) => console.debug("Loaded", fs.length, "features from", url))
|
||||
.catch((err) => console.warn("Could not load ", url, "due to", err))
|
||||
}
|
||||
this.features = eventsource
|
||||
|
@ -105,7 +105,7 @@ export default class GeoJsonSource implements FeatureSource {
|
|||
let i = 0
|
||||
let skipped = 0
|
||||
for (const feature of json.features) {
|
||||
if(feature.geometry.type === "Point"){
|
||||
if (feature.geometry.type === "Point") {
|
||||
// See https://github.com/maproulette/maproulette-backend/issues/242
|
||||
feature.geometry.coordinates = feature.geometry.coordinates.map(Number)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,9 @@ export class LastClickFeatureSource implements WritableFeatureSource {
|
|||
}
|
||||
|
||||
const renderings = Utils.Dedup(
|
||||
allPresets.map((uiElem) => Utils.runningFromConsole ? "" : uiElem.ConstructElement().innerHTML)
|
||||
allPresets.map((uiElem) =>
|
||||
Utils.runningFromConsole ? "" : uiElem.ConstructElement().innerHTML
|
||||
)
|
||||
)
|
||||
|
||||
const properties = {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import GeoJsonSource from "./GeoJsonSource"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import {FeatureSource} from "../FeatureSource"
|
||||
import {Or} from "../../Tags/Or"
|
||||
import { FeatureSource } from "../FeatureSource"
|
||||
import { Or } from "../../Tags/Or"
|
||||
import FeatureSwitchState from "../../State/FeatureSwitchState"
|
||||
import OverpassFeatureSource from "./OverpassFeatureSource"
|
||||
import {Store, UIEventSource} from "../../UIEventSource"
|
||||
import { Store, UIEventSource } from "../../UIEventSource"
|
||||
import OsmFeatureSource from "./OsmFeatureSource"
|
||||
import FeatureSourceMerger from "./FeatureSourceMerger"
|
||||
import DynamicGeoJsonTileSource from "../TiledFeatureSource/DynamicGeoJsonTileSource"
|
||||
import {BBox} from "../../BBox"
|
||||
import { BBox } from "../../BBox"
|
||||
import LocalStorageFeatureSource from "../TiledFeatureSource/LocalStorageFeatureSource"
|
||||
import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource";
|
||||
import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
||||
/**
|
||||
* This source will fetch the needed data from various sources for the given layout.
|
||||
|
@ -41,7 +41,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
(l) =>
|
||||
new LocalStorageFeatureSource(backend, l.id, 15, mapProperties, {
|
||||
isActive: isDisplayed(l.id),
|
||||
maxAge: l.maxAgeOfCache
|
||||
maxAge: l.maxAgeOfCache,
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -127,7 +127,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
backend,
|
||||
isActive,
|
||||
patchRelations: true,
|
||||
fullNodeDatabase
|
||||
fullNodeDatabase,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { TagsFilter } from "../../Tags/TagsFilter"
|
|||
import { Feature } from "geojson"
|
||||
import FeatureSourceMerger from "../Sources/FeatureSourceMerger"
|
||||
import OsmObjectDownloader from "../../Osm/OsmObjectDownloader"
|
||||
import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource";
|
||||
import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
||||
/**
|
||||
* If a tile is needed (requested via the UIEventSource in the constructor), will download the appropriate tile and pass it via 'handleTile'
|
||||
|
@ -24,16 +24,16 @@ export default class OsmFeatureSource extends FeatureSourceMerger {
|
|||
/**
|
||||
* If given: this featureSwitch will not update if the store contains 'false'
|
||||
*/
|
||||
isActive?: Store<boolean>,
|
||||
patchRelations?: true | boolean,
|
||||
isActive?: Store<boolean>
|
||||
patchRelations?: true | boolean
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
};
|
||||
}
|
||||
|
||||
public readonly isRunning: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
|
||||
private readonly _downloadedTiles: Set<number> = new Set<number>()
|
||||
private readonly _downloadedData: Feature[][] = []
|
||||
private readonly _patchRelations: boolean;
|
||||
private readonly _patchRelations: boolean
|
||||
/**
|
||||
* Downloads data directly from the OSM-api within the given bounds.
|
||||
* All features which match the TagsFilter 'allowedFeatures' are kept and converted into geojson
|
||||
|
@ -45,12 +45,12 @@ export default class OsmFeatureSource extends FeatureSourceMerger {
|
|||
/**
|
||||
* If given: this featureSwitch will not update if the store contains 'false'
|
||||
*/
|
||||
isActive?: Store<boolean>,
|
||||
patchRelations?: true | boolean,
|
||||
isActive?: Store<boolean>
|
||||
patchRelations?: true | boolean
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
}) {
|
||||
super()
|
||||
this.options = options;
|
||||
this.options = options
|
||||
this._bounds = options.bounds
|
||||
this.allowedTags = options.allowedFeatures
|
||||
this.isActive = options.isActive ?? new ImmutableStore(true)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {FeatureSource} from "../FeatureSource"
|
||||
import {ImmutableStore, Store} from "../../UIEventSource"
|
||||
import {Feature} from "geojson"
|
||||
import { FeatureSource } from "../FeatureSource"
|
||||
import { ImmutableStore, Store } from "../../UIEventSource"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
/**
|
||||
* A simple, read only feature store.
|
||||
|
@ -8,13 +8,7 @@ import {Feature} from "geojson"
|
|||
export default class StaticFeatureSource<T extends Feature = Feature> implements FeatureSource<T> {
|
||||
public readonly features: Store<T[]>
|
||||
|
||||
constructor(
|
||||
features:
|
||||
| Store<T[]>
|
||||
| T[]
|
||||
| { features: T[] }
|
||||
| { features: Store<T[]> }
|
||||
) {
|
||||
constructor(features: Store<T[]> | T[] | { features: T[] } | { features: Store<T[]> }) {
|
||||
if (features === undefined) {
|
||||
throw "Static feature source received undefined as source"
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {FeatureSource, FeatureSourceForLayer} from "../FeatureSource"
|
||||
import { FeatureSource, FeatureSourceForLayer } from "../FeatureSource"
|
||||
import StaticFeatureSource from "./StaticFeatureSource"
|
||||
import {BBox} from "../../BBox"
|
||||
import { BBox } from "../../BBox"
|
||||
import FilteredLayer from "../../../Models/FilteredLayer"
|
||||
import {Store} from "../../UIEventSource"
|
||||
import {Feature} from "geojson";
|
||||
import { Store } from "../../UIEventSource"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
/**
|
||||
* Results in a feature source which has all the elements that touch the given features
|
||||
|
@ -30,7 +30,10 @@ export default class BBoxFeatureSource<T extends Feature = Feature> extends Stat
|
|||
}
|
||||
}
|
||||
|
||||
export class BBoxFeatureSourceForLayer<T extends Feature = Feature> extends BBoxFeatureSource<T> implements FeatureSourceForLayer {
|
||||
export class BBoxFeatureSourceForLayer<T extends Feature = Feature>
|
||||
extends BBoxFeatureSource<T>
|
||||
implements FeatureSourceForLayer
|
||||
{
|
||||
readonly layer: FilteredLayer
|
||||
|
||||
constructor(features: FeatureSourceForLayer<T>, mustTouch: Store<BBox>) {
|
||||
|
|
|
@ -72,7 +72,9 @@ export default class DynamicGeoJsonTileSource extends DynamicTileSource {
|
|||
if (!isWhiteListed) {
|
||||
console.debug(
|
||||
"Not downloading tile",
|
||||
zxy,"for layer",layer.id,
|
||||
zxy,
|
||||
"for layer",
|
||||
layer.id,
|
||||
"as it is not on the whitelist"
|
||||
)
|
||||
return undefined
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import {OsmNode, OsmObject, OsmWay} from "../../Osm/OsmObject"
|
||||
import {UIEventSource} from "../../UIEventSource"
|
||||
import {BBox} from "../../BBox";
|
||||
import StaticFeatureSource from "../Sources/StaticFeatureSource";
|
||||
import {Tiles} from "../../../Models/TileRange";
|
||||
import { OsmNode, OsmObject, OsmWay } from "../../Osm/OsmObject"
|
||||
import { UIEventSource } from "../../UIEventSource"
|
||||
import { BBox } from "../../BBox"
|
||||
import StaticFeatureSource from "../Sources/StaticFeatureSource"
|
||||
import { Tiles } from "../../../Models/TileRange"
|
||||
|
||||
export default class FullNodeDatabaseSource {
|
||||
|
||||
private readonly loadedTiles = new Map<number, Map<number, OsmNode>>()
|
||||
private readonly nodeByIds = new Map<number, OsmNode>()
|
||||
private readonly parentWays = new Map<number, UIEventSource<OsmWay[]>>()
|
||||
|
@ -13,7 +12,7 @@ export default class FullNodeDatabaseSource {
|
|||
private smallestZoom = 99
|
||||
private largestZoom = 0
|
||||
|
||||
public handleOsmJson(osmJson: any, z: number, x: number, y: number) : void {
|
||||
public handleOsmJson(osmJson: any, z: number, x: number, y: number): void {
|
||||
const allObjects = OsmObject.ParseObjects(osmJson.elements)
|
||||
const nodesById = new Map<number, OsmNode>()
|
||||
|
||||
|
@ -81,14 +80,14 @@ export default class FullNodeDatabaseSource {
|
|||
* Gets (at least) all nodes which are part of this BBOX; might also return some nodes that fall outside of the bbox but are closeby
|
||||
* @param bbox
|
||||
*/
|
||||
getNodesWithin(bbox: BBox) : Map<number, OsmNode>{
|
||||
getNodesWithin(bbox: BBox): Map<number, OsmNode> {
|
||||
const allById = new Map<number, OsmNode>()
|
||||
for (let z = this.smallestZoom; z < this.largestZoom; z++) {
|
||||
const range = Tiles.tileRangeFrom(bbox, z)
|
||||
Tiles.MapRange(range, (x, y ) => {
|
||||
Tiles.MapRange(range, (x, y) => {
|
||||
const tileId = Tiles.tile_index(z, x, y)
|
||||
const nodesById = this.loadedTiles.get(tileId)
|
||||
nodesById?.forEach((v,k) => allById.set(k,v))
|
||||
nodesById?.forEach((v, k) => allById.set(k, v))
|
||||
})
|
||||
}
|
||||
return allById
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import DynamicTileSource from "./DynamicTileSource"
|
||||
import {Store} from "../../UIEventSource"
|
||||
import {BBox} from "../../BBox"
|
||||
import { Store } from "../../UIEventSource"
|
||||
import { BBox } from "../../BBox"
|
||||
import TileLocalStorage from "../Actors/TileLocalStorage"
|
||||
import {Feature} from "geojson"
|
||||
import { Feature } from "geojson"
|
||||
import StaticFeatureSource from "../Sources/StaticFeatureSource"
|
||||
|
||||
export default class LocalStorageFeatureSource extends DynamicTileSource {
|
||||
|
@ -15,26 +15,27 @@ export default class LocalStorageFeatureSource extends DynamicTileSource {
|
|||
zoom: Store<number>
|
||||
},
|
||||
options?: {
|
||||
isActive?: Store<boolean>,
|
||||
isActive?: Store<boolean>
|
||||
maxAge?: number // In seconds
|
||||
}
|
||||
) {
|
||||
const storage = TileLocalStorage.construct<Feature[]>(backend, layername, options?.maxAge ?? 24 * 60 * 60)
|
||||
const storage = TileLocalStorage.construct<Feature[]>(
|
||||
backend,
|
||||
layername,
|
||||
options?.maxAge ?? 24 * 60 * 60
|
||||
)
|
||||
super(
|
||||
zoomlevel,
|
||||
(tileIndex) =>
|
||||
new StaticFeatureSource(
|
||||
storage
|
||||
.getTileSource(tileIndex)
|
||||
.mapD((features) => {
|
||||
if (features.length === undefined) {
|
||||
console.trace("These are not features:", features)
|
||||
storage.invalidate(zoomlevel, tileIndex)
|
||||
return []
|
||||
}
|
||||
return features.filter((f) => !f.properties.id.match(/(node|way)\/-[0-9]+/));
|
||||
}
|
||||
)
|
||||
storage.getTileSource(tileIndex).mapD((features) => {
|
||||
if (features.length === undefined) {
|
||||
console.trace("These are not features:", features)
|
||||
storage.invalidate(zoomlevel, tileIndex)
|
||||
return []
|
||||
}
|
||||
return features.filter((f) => !f.properties.id.match(/(node|way)\/-[0-9]+/))
|
||||
})
|
||||
),
|
||||
mapProperties,
|
||||
options
|
||||
|
|
|
@ -408,7 +408,10 @@ export class GeoOperations {
|
|||
/**
|
||||
* Calculates line intersection between two features.
|
||||
*/
|
||||
public static LineIntersections(feature: Feature<LineString | MultiLineString | Polygon | MultiPolygon>, otherFeature: Feature<LineString | MultiLineString | Polygon | MultiPolygon>): [number, number][] {
|
||||
public static LineIntersections(
|
||||
feature: Feature<LineString | MultiLineString | Polygon | MultiPolygon>,
|
||||
otherFeature: Feature<LineString | MultiLineString | Polygon | MultiPolygon>
|
||||
): [number, number][] {
|
||||
return turf
|
||||
.lineIntersect(feature, otherFeature)
|
||||
.features.map((p) => <[number, number]>p.geometry.coordinates)
|
||||
|
@ -420,8 +423,7 @@ export class GeoOperations {
|
|||
* @param features
|
||||
* @param zoomlevel
|
||||
*/
|
||||
public static spreadIntoBboxes(features: Feature[], zoomlevel: number) : Map<number, Feature[]> {
|
||||
|
||||
public static spreadIntoBboxes(features: Feature[], zoomlevel: number): Map<number, Feature[]> {
|
||||
const perBbox = new Map<number, Feature[]>()
|
||||
|
||||
for (const feature of features) {
|
||||
|
@ -430,7 +432,7 @@ export class GeoOperations {
|
|||
Tiles.MapRange(tilerange, (x, y) => {
|
||||
const tileNumber = Tiles.tile_index(zoomlevel, x, y)
|
||||
let newFeatureList = perBbox.get(tileNumber)
|
||||
if(newFeatureList === undefined){
|
||||
if (newFeatureList === undefined) {
|
||||
newFeatureList = []
|
||||
perBbox.set(tileNumber, newFeatureList)
|
||||
}
|
||||
|
@ -703,18 +705,18 @@ export class GeoOperations {
|
|||
|
||||
public static along(a: Coord, b: Coord, distanceMeter: number): Coord {
|
||||
return turf.along(
|
||||
<any> {
|
||||
type:"Feature",
|
||||
geometry:{
|
||||
type:"LineString",
|
||||
coordinates: [a, b]
|
||||
}
|
||||
}, distanceMeter, {units: "meters"}
|
||||
|
||||
<any>{
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: [a, b],
|
||||
},
|
||||
},
|
||||
distanceMeter,
|
||||
{ units: "meters" }
|
||||
).geometry.coordinates
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns 'true' if one feature contains the other feature
|
||||
*
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Mapillary } from "./Mapillary";
|
||||
import { WikimediaImageProvider } from "./WikimediaImageProvider";
|
||||
import { Imgur } from "./Imgur";
|
||||
import GenericImageProvider from "./GenericImageProvider";
|
||||
import { Store, UIEventSource } from "../UIEventSource";
|
||||
import ImageProvider, { ProvidedImage } from "./ImageProvider";
|
||||
import { WikidataImageProvider } from "./WikidataImageProvider";
|
||||
import { Mapillary } from "./Mapillary"
|
||||
import { WikimediaImageProvider } from "./WikimediaImageProvider"
|
||||
import { Imgur } from "./Imgur"
|
||||
import GenericImageProvider from "./GenericImageProvider"
|
||||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import ImageProvider, { ProvidedImage } from "./ImageProvider"
|
||||
import { WikidataImageProvider } from "./WikidataImageProvider"
|
||||
|
||||
/**
|
||||
* A generic 'from the interwebz' image picker, without attribution
|
||||
|
@ -44,7 +44,10 @@ export default class AllImageProviders {
|
|||
UIEventSource<ProvidedImage[]>
|
||||
>()
|
||||
|
||||
public static LoadImagesFor(tags: Store<Record<string, string>>, tagKey?: string[]): Store<ProvidedImage[]> {
|
||||
public static LoadImagesFor(
|
||||
tags: Store<Record<string, string>>,
|
||||
tagKey?: string[]
|
||||
): Store<ProvidedImage[]> {
|
||||
if (tags.data.id === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
|
|
@ -80,12 +80,12 @@ export default class Maproulette {
|
|||
* Maproulette.codeToIndex("qdsf") // => undefined
|
||||
*
|
||||
*/
|
||||
public static codeToIndex(code: string) : number | undefined{
|
||||
if(code === "Created"){
|
||||
public static codeToIndex(code: string): number | undefined {
|
||||
if (code === "Created") {
|
||||
return Maproulette.STATUS_OPEN
|
||||
}
|
||||
for (let i = 0; i < 9; i++) {
|
||||
if(Maproulette.STATUS_MEANING[""+i] === code){
|
||||
if (Maproulette.STATUS_MEANING["" + i] === code) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import SimpleMetaTaggers, {MetataggingState, SimpleMetaTagger} from "./SimpleMetaTagger"
|
||||
import {ExtraFuncParams, ExtraFunctions, ExtraFuncType} from "./ExtraFunctions"
|
||||
import SimpleMetaTaggers, { MetataggingState, SimpleMetaTagger } from "./SimpleMetaTagger"
|
||||
import { ExtraFuncParams, ExtraFunctions, ExtraFuncType } from "./ExtraFunctions"
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||
import {Feature} from "geojson"
|
||||
import { Feature } from "geojson"
|
||||
import FeaturePropertiesStore from "./FeatureSource/Actors/FeaturePropertiesStore"
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
||||
import {GeoIndexedStoreForLayer} from "./FeatureSource/Actors/GeoIndexedStore"
|
||||
import {IndexedFeatureSource} from "./FeatureSource/FeatureSource"
|
||||
import { GeoIndexedStoreForLayer } from "./FeatureSource/Actors/GeoIndexedStore"
|
||||
import { IndexedFeatureSource } from "./FeatureSource/FeatureSource"
|
||||
import OsmObjectDownloader from "./Osm/OsmObjectDownloader"
|
||||
import {Utils} from "../Utils";
|
||||
import {UIEventSource} from "./UIEventSource";
|
||||
import { Utils } from "../Utils"
|
||||
import { UIEventSource } from "./UIEventSource"
|
||||
|
||||
/**
|
||||
* Metatagging adds various tags to the elements, e.g. lat, lon, surface area, ...
|
||||
|
@ -18,7 +18,10 @@ import {UIEventSource} from "./UIEventSource";
|
|||
export default class MetaTagging {
|
||||
private static errorPrintCount = 0
|
||||
private static readonly stopErrorOutputAt = 10
|
||||
private static retaggingFuncCache = new Map<string, ((feature: Feature, propertiesStore: UIEventSource<any>) => void)[]>()
|
||||
private static retaggingFuncCache = new Map<
|
||||
string,
|
||||
((feature: Feature, propertiesStore: UIEventSource<any>) => void)[]
|
||||
>()
|
||||
|
||||
constructor(state: {
|
||||
layout: LayoutConfig
|
||||
|
@ -96,7 +99,7 @@ export default class MetaTagging {
|
|||
// The calculated functions - per layer - which add the new keys
|
||||
// Calculated functions are defined by the layer
|
||||
const layerFuncs = this.createRetaggingFunc(layer, ExtraFunctions.constructHelpers(params))
|
||||
const state: MetataggingState = {layout, osmObjectDownloader}
|
||||
const state: MetataggingState = { layout, osmObjectDownloader }
|
||||
|
||||
let atLeastOneFeatureChanged = false
|
||||
let strictlyEvaluated = 0
|
||||
|
@ -177,20 +180,20 @@ export default class MetaTagging {
|
|||
}
|
||||
|
||||
public static createExtraFuncParams(state: {
|
||||
indexedFeatures: IndexedFeatureSource,
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
||||
}) {
|
||||
return {
|
||||
getFeatureById: (id) => state.indexedFeatures.featuresById.data.get(id),
|
||||
getFeaturesWithin: (layerId, bbox) => {
|
||||
if (layerId === '*' || layerId === null || layerId === undefined) {
|
||||
if (layerId === "*" || layerId === null || layerId === undefined) {
|
||||
const feats: Feature[][] = []
|
||||
state.perLayer.forEach((layer) => {
|
||||
feats.push(layer.GetFeaturesWithin(bbox))
|
||||
})
|
||||
return feats
|
||||
}
|
||||
return [state.perLayer.get(layerId).GetFeaturesWithin(bbox)];
|
||||
return [state.perLayer.get(layerId).GetFeaturesWithin(bbox)]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -202,23 +205,30 @@ export default class MetaTagging {
|
|||
* @param layerId
|
||||
* @private
|
||||
*/
|
||||
private static createFunctionForFeature([key, code, isStrict]: [string, string, boolean],
|
||||
helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>,
|
||||
layerId: string = "unkown layer"
|
||||
private static createFunctionForFeature(
|
||||
[key, code, isStrict]: [string, string, boolean],
|
||||
helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>,
|
||||
layerId: string = "unkown layer"
|
||||
): ((feature: Feature, propertiesStore?: UIEventSource<any>) => void) | undefined {
|
||||
if (code === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
||||
const calculateAndAssign: ((feat: Feature, store?: UIEventSource<any>) => string | any) = (feat, store) => {
|
||||
const calculateAndAssign: (feat: Feature, store?: UIEventSource<any>) => string | any = (
|
||||
feat,
|
||||
store
|
||||
) => {
|
||||
try {
|
||||
let result = new Function("feat", "{" + ExtraFunctions.types.join(", ") + "}", "return " + code + ";")(feat, helperFunctions)
|
||||
let result = new Function(
|
||||
"feat",
|
||||
"{" + ExtraFunctions.types.join(", ") + "}",
|
||||
"return " + code + ";"
|
||||
)(feat, helperFunctions)
|
||||
if (result === "") {
|
||||
result = undefined
|
||||
}
|
||||
const oldValue= feat.properties[key]
|
||||
if(oldValue == result){
|
||||
const oldValue = feat.properties[key]
|
||||
if (oldValue == result) {
|
||||
return oldValue
|
||||
}
|
||||
delete feat.properties[key]
|
||||
|
@ -229,16 +239,16 @@ export default class MetaTagging {
|
|||
if (MetaTagging.errorPrintCount < MetaTagging.stopErrorOutputAt) {
|
||||
console.warn(
|
||||
"Could not calculate a " +
|
||||
(isStrict ? "strict " : "") +
|
||||
" calculated tag for key " +
|
||||
key +
|
||||
" defined by " +
|
||||
code +
|
||||
" (in layer" +
|
||||
layerId +
|
||||
") due to \n" +
|
||||
e +
|
||||
"\n. Are you the theme creator? Doublecheck your code. Note that the metatags might not be stable on new features",
|
||||
(isStrict ? "strict " : "") +
|
||||
" calculated tag for key " +
|
||||
key +
|
||||
" defined by " +
|
||||
code +
|
||||
" (in layer" +
|
||||
layerId +
|
||||
") due to \n" +
|
||||
e +
|
||||
"\n. Are you the theme creator? Doublecheck your code. Note that the metatags might not be stable on new features",
|
||||
e,
|
||||
e.stack
|
||||
)
|
||||
|
@ -276,9 +286,12 @@ export default class MetaTagging {
|
|||
return undefined
|
||||
}
|
||||
|
||||
let functions: ((feature: Feature, propertiesStore?: UIEventSource<any>) => void)[] = MetaTagging.retaggingFuncCache.get(layer.id)
|
||||
let functions: ((feature: Feature, propertiesStore?: UIEventSource<any>) => void)[] =
|
||||
MetaTagging.retaggingFuncCache.get(layer.id)
|
||||
if (functions === undefined) {
|
||||
functions = calculatedTags.map(spec => this.createFunctionForFeature(spec, helpers, layer.id))
|
||||
functions = calculatedTags.map((spec) =>
|
||||
this.createFunctionForFeature(spec, helpers, layer.id)
|
||||
)
|
||||
MetaTagging.retaggingFuncCache.set(layer.id, functions)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
import {OsmCreateAction, PreviewableAction} from "./OsmChangeAction"
|
||||
import {Tag} from "../../Tags/Tag"
|
||||
import {Changes} from "../Changes"
|
||||
import {ChangeDescription} from "./ChangeDescription"
|
||||
import { OsmCreateAction, PreviewableAction } from "./OsmChangeAction"
|
||||
import { Tag } from "../../Tags/Tag"
|
||||
import { Changes } from "../Changes"
|
||||
import { ChangeDescription } from "./ChangeDescription"
|
||||
import CreateNewWayAction from "./CreateNewWayAction"
|
||||
import CreateWayWithPointReuseAction, {MergePointConfig} from "./CreateWayWithPointReuseAction"
|
||||
import {And} from "../../Tags/And"
|
||||
import {TagUtils} from "../../Tags/TagUtils"
|
||||
import {FeatureSource, IndexedFeatureSource} from "../../FeatureSource/FeatureSource"
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig";
|
||||
import {Position} from "geojson";
|
||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource";
|
||||
import CreateWayWithPointReuseAction, { MergePointConfig } from "./CreateWayWithPointReuseAction"
|
||||
import { And } from "../../Tags/And"
|
||||
import { TagUtils } from "../../Tags/TagUtils"
|
||||
import { FeatureSource, IndexedFeatureSource } from "../../FeatureSource/FeatureSource"
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
||||
import { Position } from "geojson"
|
||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
||||
/**
|
||||
* More or less the same as 'CreateNewWay', except that it'll try to reuse already existing points
|
||||
*/
|
||||
export default class CreateMultiPolygonWithPointReuseAction extends OsmCreateAction implements PreviewableAction {
|
||||
export default class CreateMultiPolygonWithPointReuseAction
|
||||
extends OsmCreateAction
|
||||
implements PreviewableAction
|
||||
{
|
||||
public newElementId: string = undefined
|
||||
public newElementIdNumber: number = undefined
|
||||
private readonly _tags: Tag[]
|
||||
|
@ -29,9 +32,9 @@ export default class CreateMultiPolygonWithPointReuseAction extends OsmCreateAct
|
|||
outerRingCoordinates: Position[],
|
||||
innerRingsCoordinates: Position[][],
|
||||
state: {
|
||||
layout: LayoutConfig;
|
||||
changes: Changes;
|
||||
indexedFeatures: IndexedFeatureSource,
|
||||
layout: LayoutConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
},
|
||||
config: MergePointConfig[],
|
||||
|
@ -43,7 +46,7 @@ export default class CreateMultiPolygonWithPointReuseAction extends OsmCreateAct
|
|||
this.theme = state?.layout?.id ?? ""
|
||||
this.createOuterWay = new CreateWayWithPointReuseAction(
|
||||
[],
|
||||
<[number,number][]> outerRingCoordinates,
|
||||
<[number, number][]>outerRingCoordinates,
|
||||
state,
|
||||
config
|
||||
)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {ChangeDescription} from "./ChangeDescription"
|
||||
import {OsmCreateAction} from "./OsmChangeAction"
|
||||
import {Changes} from "../Changes"
|
||||
import {Tag} from "../../Tags/Tag"
|
||||
import { ChangeDescription } from "./ChangeDescription"
|
||||
import { OsmCreateAction } from "./OsmChangeAction"
|
||||
import { Changes } from "../Changes"
|
||||
import { Tag } from "../../Tags/Tag"
|
||||
import CreateNewNodeAction from "./CreateNewNodeAction"
|
||||
import {And} from "../../Tags/And"
|
||||
import { And } from "../../Tags/And"
|
||||
|
||||
export default class CreateNewWayAction extends OsmCreateAction {
|
||||
public newElementId: string = undefined
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import {OsmCreateAction, PreviewableAction} from "./OsmChangeAction"
|
||||
import {Tag} from "../../Tags/Tag"
|
||||
import {Changes} from "../Changes"
|
||||
import {ChangeDescription} from "./ChangeDescription"
|
||||
import {BBox} from "../../BBox"
|
||||
import {TagsFilter} from "../../Tags/TagsFilter"
|
||||
import {GeoOperations} from "../../GeoOperations"
|
||||
import {FeatureSource, IndexedFeatureSource} from "../../FeatureSource/FeatureSource"
|
||||
import { OsmCreateAction, PreviewableAction } from "./OsmChangeAction"
|
||||
import { Tag } from "../../Tags/Tag"
|
||||
import { Changes } from "../Changes"
|
||||
import { ChangeDescription } from "./ChangeDescription"
|
||||
import { BBox } from "../../BBox"
|
||||
import { TagsFilter } from "../../Tags/TagsFilter"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
import { FeatureSource, IndexedFeatureSource } from "../../FeatureSource/FeatureSource"
|
||||
import StaticFeatureSource from "../../FeatureSource/Sources/StaticFeatureSource"
|
||||
import CreateNewNodeAction from "./CreateNewNodeAction"
|
||||
import CreateNewWayAction from "./CreateNewWayAction"
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig";
|
||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource";
|
||||
import {Position} from "geojson";
|
||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
import { Position } from "geojson"
|
||||
|
||||
export interface MergePointConfig {
|
||||
withinRangeOfM: number
|
||||
|
@ -56,7 +56,10 @@ interface CoordinateInfo {
|
|||
/**
|
||||
* More or less the same as 'CreateNewWay', except that it'll try to reuse already existing points
|
||||
*/
|
||||
export default class CreateWayWithPointReuseAction extends OsmCreateAction implements PreviewableAction {
|
||||
export default class CreateWayWithPointReuseAction
|
||||
extends OsmCreateAction
|
||||
implements PreviewableAction
|
||||
{
|
||||
public newElementId: string = undefined
|
||||
public newElementIdNumber: number = undefined
|
||||
private readonly _tags: Tag[]
|
||||
|
@ -66,9 +69,9 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction imple
|
|||
*/
|
||||
private readonly _coordinateInfo: CoordinateInfo[]
|
||||
private readonly _state: {
|
||||
layout: LayoutConfig;
|
||||
changes: Changes;
|
||||
indexedFeatures: IndexedFeatureSource,
|
||||
layout: LayoutConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
}
|
||||
private readonly _config: MergePointConfig[]
|
||||
|
@ -77,9 +80,9 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction imple
|
|||
tags: Tag[],
|
||||
coordinates: Position[],
|
||||
state: {
|
||||
layout: LayoutConfig;
|
||||
changes: Changes;
|
||||
indexedFeatures: IndexedFeatureSource,
|
||||
layout: LayoutConfig
|
||||
changes: Changes
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
},
|
||||
config: MergePointConfig[]
|
||||
|
@ -90,7 +93,7 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction imple
|
|||
this._config = config
|
||||
|
||||
// The main logic of this class: the coordinateInfo contains all the changes
|
||||
this._coordinateInfo = this.CalculateClosebyNodes(<[number,number][]> coordinates)
|
||||
this._coordinateInfo = this.CalculateClosebyNodes(<[number, number][]>coordinates)
|
||||
}
|
||||
|
||||
public async getPreview(): Promise<FeatureSource> {
|
||||
|
@ -245,7 +248,7 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction imple
|
|||
},
|
||||
})
|
||||
}
|
||||
nodeIdsToUse.push({lat, lon, nodeId: id})
|
||||
nodeIdsToUse.push({ lat, lon, nodeId: id })
|
||||
}
|
||||
|
||||
const newWay = new CreateNewWayAction(this._tags, nodeIdsToUse, {
|
||||
|
@ -321,7 +324,7 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction imple
|
|||
if (!config.ifMatches.matchesProperties(node.properties)) {
|
||||
continue
|
||||
}
|
||||
closebyNodes.push({node, d, config})
|
||||
closebyNodes.push({ node, d, config })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { And } from "../../Tags/And"
|
|||
import { Tag } from "../../Tags/Tag"
|
||||
import { OsmId } from "../../../Models/OsmFeature"
|
||||
import { Utils } from "../../../Utils"
|
||||
import OsmObjectDownloader from "../OsmObjectDownloader";
|
||||
import OsmObjectDownloader from "../OsmObjectDownloader"
|
||||
|
||||
export default class DeleteAction extends OsmChangeAction {
|
||||
private readonly _softDeletionTags: TagsFilter
|
||||
|
@ -72,9 +72,11 @@ export default class DeleteAction extends OsmChangeAction {
|
|||
changes: Changes,
|
||||
object?: OsmObject
|
||||
): Promise<ChangeDescription[]> {
|
||||
const osmObject = object ?? (await new OsmObjectDownloader(changes.backend, changes).DownloadObjectAsync(this._id))
|
||||
const osmObject =
|
||||
object ??
|
||||
(await new OsmObjectDownloader(changes.backend, changes).DownloadObjectAsync(this._id))
|
||||
|
||||
if(osmObject === "deleted"){
|
||||
if (osmObject === "deleted") {
|
||||
// already deleted in the meantime - no more changes necessary
|
||||
return []
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
import { Changes } from "../Changes"
|
||||
import { ChangeDescription } from "./ChangeDescription"
|
||||
import {FeatureSource} from "../../FeatureSource/FeatureSource";
|
||||
import { FeatureSource } from "../../FeatureSource/FeatureSource"
|
||||
|
||||
export default abstract class OsmChangeAction {
|
||||
public readonly trackStatistics: boolean
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import OsmChangeAction, {PreviewableAction} from "./OsmChangeAction"
|
||||
import {Changes} from "../Changes"
|
||||
import {ChangeDescription} from "./ChangeDescription"
|
||||
import {Tag} from "../../Tags/Tag"
|
||||
import {FeatureSource} from "../../FeatureSource/FeatureSource"
|
||||
import {OsmNode, OsmObject, OsmWay} from "../OsmObject"
|
||||
import {GeoOperations} from "../../GeoOperations"
|
||||
import OsmChangeAction, { PreviewableAction } from "./OsmChangeAction"
|
||||
import { Changes } from "../Changes"
|
||||
import { ChangeDescription } from "./ChangeDescription"
|
||||
import { Tag } from "../../Tags/Tag"
|
||||
import { FeatureSource } from "../../FeatureSource/FeatureSource"
|
||||
import { OsmNode, OsmObject, OsmWay } from "../OsmObject"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
import StaticFeatureSource from "../../FeatureSource/Sources/StaticFeatureSource"
|
||||
import CreateNewNodeAction from "./CreateNewNodeAction"
|
||||
import ChangeTagAction from "./ChangeTagAction"
|
||||
import {And} from "../../Tags/And"
|
||||
import {Utils} from "../../../Utils"
|
||||
import {OsmConnection} from "../OsmConnection"
|
||||
import {Feature} from "@turf/turf"
|
||||
import {Geometry, LineString, Point} from "geojson"
|
||||
import { And } from "../../Tags/And"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { OsmConnection } from "../OsmConnection"
|
||||
import { Feature } from "@turf/turf"
|
||||
import { Geometry, LineString, Point } from "geojson"
|
||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
||||
export default class ReplaceGeometryAction extends OsmChangeAction implements PreviewableAction{
|
||||
export default class ReplaceGeometryAction extends OsmChangeAction implements PreviewableAction {
|
||||
/**
|
||||
* The target feature - mostly used for the metadata
|
||||
*/
|
||||
|
@ -45,7 +45,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
public readonly newElementId: string
|
||||
constructor(
|
||||
state: {
|
||||
osmConnection: OsmConnection,
|
||||
osmConnection: OsmConnection
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
},
|
||||
feature: any,
|
||||
|
@ -460,7 +460,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
}
|
||||
}
|
||||
|
||||
console.log("Adding tags", this.newTags,"to conflated way nr", this.wayToReplaceId)
|
||||
console.log("Adding tags", this.newTags, "to conflated way nr", this.wayToReplaceId)
|
||||
if (this.newTags !== undefined && this.newTags.length > 0) {
|
||||
const addExtraTags = new ChangeTagAction(
|
||||
this.wayToReplaceId,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {OsmWay} from "../OsmObject"
|
||||
import {Changes} from "../Changes"
|
||||
import {GeoOperations} from "../../GeoOperations"
|
||||
import { OsmWay } from "../OsmObject"
|
||||
import { Changes } from "../Changes"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
import OsmChangeAction from "./OsmChangeAction"
|
||||
import {ChangeDescription} from "./ChangeDescription"
|
||||
import { ChangeDescription } from "./ChangeDescription"
|
||||
import RelationSplitHandler from "./RelationSplitHandler"
|
||||
import {Feature, LineString} from "geojson"
|
||||
import { Feature, LineString } from "geojson"
|
||||
import OsmObjectDownloader from "../OsmObjectDownloader"
|
||||
|
||||
interface SplitInfo {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import {OsmNode, OsmObject, OsmRelation, OsmWay} from "./OsmObject"
|
||||
import {Store, UIEventSource} from "../UIEventSource"
|
||||
import { OsmNode, OsmObject, OsmRelation, OsmWay } from "./OsmObject"
|
||||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import Constants from "../../Models/Constants"
|
||||
import OsmChangeAction from "./Actions/OsmChangeAction"
|
||||
import {ChangeDescription, ChangeDescriptionTools} from "./Actions/ChangeDescription"
|
||||
import {Utils} from "../../Utils"
|
||||
import {LocalStorageSource} from "../Web/LocalStorageSource"
|
||||
import { ChangeDescription, ChangeDescriptionTools } from "./Actions/ChangeDescription"
|
||||
import { Utils } from "../../Utils"
|
||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
import SimpleMetaTagger from "../SimpleMetaTagger"
|
||||
import {FeatureSource, IndexedFeatureSource} from "../FeatureSource/FeatureSource"
|
||||
import {GeoLocationPointProperties} from "../State/GeoLocationState"
|
||||
import {GeoOperations} from "../GeoOperations"
|
||||
import {ChangesetHandler, ChangesetTag} from "./ChangesetHandler"
|
||||
import {OsmConnection} from "./OsmConnection"
|
||||
import { FeatureSource, IndexedFeatureSource } from "../FeatureSource/FeatureSource"
|
||||
import { GeoLocationPointProperties } from "../State/GeoLocationState"
|
||||
import { GeoOperations } from "../GeoOperations"
|
||||
import { ChangesetHandler, ChangesetTag } from "./ChangesetHandler"
|
||||
import { OsmConnection } from "./OsmConnection"
|
||||
import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore"
|
||||
import OsmObjectDownloader from "./OsmObjectDownloader"
|
||||
|
||||
|
@ -408,7 +408,7 @@ export class Changes {
|
|||
neededIds.map(async (id) => {
|
||||
try {
|
||||
const osmObj = await downloader.DownloadObjectAsync(id)
|
||||
return {id, osmObj}
|
||||
return { id, osmObj }
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"Could not download OSM-object",
|
||||
|
@ -422,7 +422,7 @@ export class Changes {
|
|||
|
||||
osmObjects = Utils.NoNull(osmObjects)
|
||||
|
||||
for (const {osmObj, id} of osmObjects) {
|
||||
for (const { osmObj, id } of osmObjects) {
|
||||
if (osmObj === "deleted") {
|
||||
pending = pending.filter((ch) => ch.type + "/" + ch.id !== id)
|
||||
}
|
||||
|
@ -573,9 +573,9 @@ export class Changes {
|
|||
)
|
||||
console.log(
|
||||
"Using current-open-changeset-" +
|
||||
theme +
|
||||
" from the preferences, got " +
|
||||
openChangeset.data
|
||||
theme +
|
||||
" from the preferences, got " +
|
||||
openChangeset.data
|
||||
)
|
||||
|
||||
return await self.flushSelectChanges(pendingChanges, openChangeset)
|
||||
|
|
|
@ -131,7 +131,8 @@ export class ChangesetHandler {
|
|||
const changeset = generateChangeXML(csId, this._remappings)
|
||||
console.log(
|
||||
"Opened a new changeset (openChangeset.data is undefined):",
|
||||
changeset, extraMetaTags
|
||||
changeset,
|
||||
extraMetaTags
|
||||
)
|
||||
const changes = await this.UploadChange(csId, changeset)
|
||||
const hasSpecialMotivationChanges = ChangesetHandler.rewriteMetaTags(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {Utils} from "../../Utils"
|
||||
import { Utils } from "../../Utils"
|
||||
import polygon_features from "../../assets/polygon-features.json"
|
||||
import OsmToGeoJson from "osmtogeojson"
|
||||
import {OsmFeature, OsmId, OsmTags, WayId} from "../../Models/OsmFeature"
|
||||
import {Feature, LineString, Polygon} from "geojson"
|
||||
import { OsmFeature, OsmId, OsmTags, WayId } from "../../Models/OsmFeature"
|
||||
import { Feature, LineString, Polygon } from "geojson"
|
||||
|
||||
export abstract class OsmObject {
|
||||
private static defaultBackend = "https://www.openstreetmap.org/"
|
||||
|
@ -198,7 +198,6 @@ export class OsmNode extends OsmObject {
|
|||
this.LoadData(extraData)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* const obj = new OsmNode(1234)
|
||||
|
@ -213,11 +212,11 @@ export class OsmNode extends OsmObject {
|
|||
*/
|
||||
ChangesetXML(changesetId: string, header?: string): string {
|
||||
let tags = this.TagsXML()
|
||||
return (
|
||||
` <node id="${this.id}" ${header ?? ""} ${changesetId ? (' changeset="' + changesetId+ '" ') : ""}${this.VersionXML()} lat="${this.lat}" lon="${this.lon}">
|
||||
return ` <node id="${this.id}" ${header ?? ""} ${
|
||||
changesetId ? ' changeset="' + changesetId + '" ' : ""
|
||||
}${this.VersionXML()} lat="${this.lat}" lon="${this.lon}">
|
||||
${tags} </node>
|
||||
`
|
||||
)
|
||||
}
|
||||
|
||||
SaveExtraData(element) {
|
||||
|
@ -269,11 +268,11 @@ export class OsmWay extends OsmObject {
|
|||
nds += ' <nd ref="' + this.nodes[node] + '"/>\n'
|
||||
}
|
||||
|
||||
return (
|
||||
` <way id="${this.id}" ${header ?? ""} ${changesetId ? ('changeset="' + changesetId + '" ') : ""} ${this.VersionXML()}>
|
||||
return ` <way id="${this.id}" ${header ?? ""} ${
|
||||
changesetId ? 'changeset="' + changesetId + '" ' : ""
|
||||
} ${this.VersionXML()}>
|
||||
${nds}${tags} </way>
|
||||
`
|
||||
)
|
||||
}
|
||||
|
||||
SaveExtraData(element, allNodes: OsmNode[]) {
|
||||
|
|
|
@ -132,7 +132,7 @@ class CountryTagger extends SimpleMetaTagger {
|
|||
CountryTagger.coder
|
||||
.GetCountryCodeAsync(lon, lat)
|
||||
.then((countries) => {
|
||||
if(!countries){
|
||||
if (!countries) {
|
||||
console.warn("Country coder returned ", countries)
|
||||
return
|
||||
}
|
||||
|
@ -315,8 +315,7 @@ export default class SimpleMetaTaggers {
|
|||
},
|
||||
(feature) => {
|
||||
Utils.AddLazyProperty(feature.properties, "_surface", () => {
|
||||
return "" + GeoOperations.surfaceAreaInSqMeters(feature)
|
||||
|
||||
return "" + GeoOperations.surfaceAreaInSqMeters(feature)
|
||||
})
|
||||
|
||||
return true
|
||||
|
|
|
@ -2,38 +2,26 @@
|
|||
* The part of the global state which initializes the feature switches, based on default values and on the layoutToUse
|
||||
*/
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import {UIEventSource} from "../UIEventSource"
|
||||
import {QueryParameters} from "../Web/QueryParameters"
|
||||
import { UIEventSource } from "../UIEventSource"
|
||||
import { QueryParameters } from "../Web/QueryParameters"
|
||||
import Constants from "../../Models/Constants"
|
||||
import {Utils} from "../../Utils"
|
||||
import { Utils } from "../../Utils"
|
||||
|
||||
class FeatureSwitchUtils {
|
||||
static initSwitch(
|
||||
key: string,
|
||||
deflt:boolean,
|
||||
documentation: string
|
||||
): UIEventSource<boolean> {
|
||||
const defaultValue = deflt
|
||||
const queryParam = QueryParameters.GetQueryParameter(
|
||||
key,
|
||||
"" + defaultValue,
|
||||
documentation
|
||||
)
|
||||
|
||||
// It takes the current layout, extracts the default value for this query parameter. A query parameter event source is then retrieved and flattened
|
||||
return queryParam.sync(
|
||||
(str) => (str === undefined ? defaultValue : str !== "false"),
|
||||
[],
|
||||
(b) => (b == defaultValue ? undefined : "" + b)
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
static initSwitch(key: string, deflt: boolean, documentation: string): UIEventSource<boolean> {
|
||||
const defaultValue = deflt
|
||||
const queryParam = QueryParameters.GetQueryParameter(key, "" + defaultValue, documentation)
|
||||
|
||||
// It takes the current layout, extracts the default value for this query parameter. A query parameter event source is then retrieved and flattened
|
||||
return queryParam.sync(
|
||||
(str) => (str === undefined ? defaultValue : str !== "false"),
|
||||
[],
|
||||
(b) => (b == defaultValue ? undefined : "" + b)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class OsmConnectionFeatureSwitches {
|
||||
|
||||
public readonly featureSwitchFakeUser: UIEventSource<boolean>
|
||||
public readonly featureSwitchApiURL: UIEventSource<string>
|
||||
|
||||
|
@ -52,8 +40,7 @@ export class OsmConnectionFeatureSwitches {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
export default class FeatureSwitchState extends OsmConnectionFeatureSwitches{
|
||||
export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
||||
/**
|
||||
* The layout that is being used in this run
|
||||
*/
|
||||
|
@ -154,7 +141,6 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches{
|
|||
"Enable the export as GeoJSON and CSV button"
|
||||
)
|
||||
|
||||
|
||||
let testingDefaultValue = false
|
||||
if (
|
||||
this.featureSwitchApiURL.data !== "osm-test" &&
|
||||
|
|
|
@ -21,7 +21,9 @@ export class GeoLocationState {
|
|||
* 'granted' means that it is granted
|
||||
* 'denied' means that we don't have access
|
||||
*/
|
||||
public readonly permission: UIEventSource<GeolocationPermissionState> = new UIEventSource("prompt")
|
||||
public readonly permission: UIEventSource<GeolocationPermissionState> = new UIEventSource(
|
||||
"prompt"
|
||||
)
|
||||
|
||||
/**
|
||||
* Important to determine e.g. if we move automatically on fix or not
|
||||
|
|
|
@ -69,7 +69,7 @@ export default class LayerState {
|
|||
new Tag("level", "" + level),
|
||||
new RegexTag("level", new RegExp("(.*;)?" + level + "(;.*)?")),
|
||||
]
|
||||
if(level === "0") {
|
||||
if (level === "0") {
|
||||
conditionsOrred.push(new Tag("level", "")) // No level tag is the same as level '0'
|
||||
}
|
||||
console.log("Setting levels filter to", conditionsOrred)
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import {OsmConnection} from "../Osm/OsmConnection"
|
||||
import {MangroveIdentity} from "../Web/MangroveReviews"
|
||||
import {Store, Stores, UIEventSource} from "../UIEventSource"
|
||||
import { OsmConnection } from "../Osm/OsmConnection"
|
||||
import { MangroveIdentity } from "../Web/MangroveReviews"
|
||||
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
||||
import StaticFeatureSource from "../FeatureSource/Sources/StaticFeatureSource"
|
||||
import {FeatureSource} from "../FeatureSource/FeatureSource"
|
||||
import {Feature} from "geojson"
|
||||
import {Utils} from "../../Utils"
|
||||
import { FeatureSource } from "../FeatureSource/FeatureSource"
|
||||
import { Feature } from "geojson"
|
||||
import { Utils } from "../../Utils"
|
||||
import translators from "../../assets/translators.json"
|
||||
import codeContributors from "../../assets/contributors.json"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import {LayerConfigJson} from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import usersettings from "../../assets/generated/layers/usersettings.json"
|
||||
import Locale from "../../UI/i18n/Locale"
|
||||
import LinkToWeblate from "../../UI/Base/LinkToWeblate"
|
||||
import FeatureSwitchState from "./FeatureSwitchState"
|
||||
import Constants from "../../Models/Constants";
|
||||
import Constants from "../../Models/Constants"
|
||||
|
||||
/**
|
||||
* The part of the state which keeps track of user-related stuff, e.g. the OSM-connection,
|
||||
|
@ -34,8 +34,8 @@ export default class UserRelatedState {
|
|||
public readonly mangroveIdentity: MangroveIdentity
|
||||
public readonly installedUserThemes: Store<string[]>
|
||||
public readonly showAllQuestionsAtOnce: UIEventSource<boolean>
|
||||
public static readonly SHOW_TAGS_VALUES = ["always","yes","full"] as const
|
||||
public readonly showTags: UIEventSource<"no" | undefined | "always" | "yes" | "full">;
|
||||
public static readonly SHOW_TAGS_VALUES = ["always", "yes", "full"] as const
|
||||
public readonly showTags: UIEventSource<"no" | undefined | "always" | "yes" | "full">
|
||||
public readonly homeLocation: FeatureSource
|
||||
public readonly language: UIEventSource<string>
|
||||
/**
|
||||
|
@ -102,26 +102,22 @@ export default class UserRelatedState {
|
|||
}
|
||||
|
||||
private static initUserRelatedState(): LayerConfig {
|
||||
try{
|
||||
|
||||
return new LayerConfig(
|
||||
<LayerConfigJson>usersettings,
|
||||
"userinformationpanel"
|
||||
)
|
||||
}catch(e){
|
||||
try {
|
||||
return new LayerConfig(<LayerConfigJson>usersettings, "userinformationpanel")
|
||||
} catch (e) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
public GetUnofficialTheme(id: string):
|
||||
| {
|
||||
id: string
|
||||
icon: string
|
||||
title: any
|
||||
shortDescription: any
|
||||
definition?: any
|
||||
isOfficial: boolean
|
||||
}
|
||||
id: string
|
||||
icon: string
|
||||
title: any
|
||||
shortDescription: any
|
||||
definition?: any
|
||||
isOfficial: boolean
|
||||
}
|
||||
| undefined {
|
||||
console.log("GETTING UNOFFICIAL THEME")
|
||||
const pref = this.osmConnection.GetLongPreference("unofficial-theme-" + id)
|
||||
|
@ -146,8 +142,8 @@ export default class UserRelatedState {
|
|||
} catch (e) {
|
||||
console.warn(
|
||||
"Removing theme " +
|
||||
id +
|
||||
" as it could not be parsed from the preferences; the content is:",
|
||||
id +
|
||||
" as it could not be parsed from the preferences; the content is:",
|
||||
str
|
||||
)
|
||||
pref.setData(null)
|
||||
|
@ -184,7 +180,7 @@ export default class UserRelatedState {
|
|||
}
|
||||
|
||||
private InitializeLanguage(availableLanguages?: string[]) {
|
||||
this.language.addCallbackAndRunD(language => Locale.language.setData(language))
|
||||
this.language.addCallbackAndRunD((language) => Locale.language.setData(language))
|
||||
Locale.language.addCallback((currentLanguage) => {
|
||||
if (Locale.showLinkToWeblate.data) {
|
||||
return true // Disable auto switching as we are in translators mode
|
||||
|
@ -262,7 +258,8 @@ export default class UserRelatedState {
|
|||
_theme: layout?.id,
|
||||
_backend: this.osmConnection.Backend(),
|
||||
_applicationOpened: new Date().toISOString(),
|
||||
_supports_sharing: (typeof window === "undefined") ? "no" : (window.navigator.share ? "yes" : "no")
|
||||
_supports_sharing:
|
||||
typeof window === "undefined" ? "no" : window.navigator.share ? "yes" : "no",
|
||||
})
|
||||
|
||||
for (const key in Constants.userJourney) {
|
||||
|
@ -297,13 +294,13 @@ export default class UserRelatedState {
|
|||
const zenLinks: { link: string; id: string }[] = Utils.NoNull([
|
||||
hasMissingTheme
|
||||
? {
|
||||
id: "theme:" + layout.id,
|
||||
link: LinkToWeblate.hrefToWeblateZen(
|
||||
language,
|
||||
"themes",
|
||||
layout.id
|
||||
),
|
||||
}
|
||||
id: "theme:" + layout.id,
|
||||
link: LinkToWeblate.hrefToWeblateZen(
|
||||
language,
|
||||
"themes",
|
||||
layout.id
|
||||
),
|
||||
}
|
||||
: undefined,
|
||||
...missingLayers.map((id) => ({
|
||||
id: "layer:" + id,
|
||||
|
@ -375,7 +372,7 @@ export default class UserRelatedState {
|
|||
// Language is managed seperately
|
||||
continue
|
||||
}
|
||||
this.osmConnection.GetPreference(key, undefined, {prefix: ""}).setData(tags[key])
|
||||
this.osmConnection.GetPreference(key, undefined, { prefix: "" }).setData(tags[key])
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {Tag} from "./Tag"
|
||||
import {TagsFilter} from "./TagsFilter"
|
||||
import { Tag } from "./Tag"
|
||||
import { TagsFilter } from "./TagsFilter"
|
||||
|
||||
export class RegexTag extends TagsFilter {
|
||||
public readonly key: RegExp | string
|
||||
|
@ -39,7 +39,6 @@ export class RegexTag extends TagsFilter {
|
|||
return fromTag === possibleRegex
|
||||
}
|
||||
return possibleRegex.test(fromTag)
|
||||
|
||||
}
|
||||
|
||||
private static source(r: string | RegExp) {
|
||||
|
@ -155,7 +154,7 @@ export class RegexTag extends TagsFilter {
|
|||
matchesProperties(tags: Record<string, string | number | boolean>): boolean {
|
||||
if (typeof this.key === "string") {
|
||||
let value = tags[this.key]
|
||||
if(!value || value === ""){
|
||||
if (!value || value === "") {
|
||||
// No tag is known, so we assume the empty string
|
||||
// If this regexTag matches the empty string, we return true, otherwise false
|
||||
// (Note: if inverted, we must reverse this)
|
||||
|
@ -176,7 +175,7 @@ export class RegexTag extends TagsFilter {
|
|||
return !this.invert
|
||||
}
|
||||
}
|
||||
if(typeof value !== "string"){
|
||||
if (typeof value !== "string") {
|
||||
value = JSON.stringify(value)
|
||||
}
|
||||
return RegexTag.doesMatch(value, this.value) != this.invert
|
||||
|
@ -188,7 +187,7 @@ export class RegexTag extends TagsFilter {
|
|||
}
|
||||
if (RegexTag.doesMatch(key, this.key)) {
|
||||
let value = tags[key] ?? ""
|
||||
if(typeof value !== "string"){
|
||||
if (typeof value !== "string") {
|
||||
value = JSON.stringify(value)
|
||||
}
|
||||
return RegexTag.doesMatch(value, this.value) != this.invert
|
||||
|
|
|
@ -47,14 +47,14 @@ export class Tag extends TagsFilter {
|
|||
// and it shouldn't be found!
|
||||
return true
|
||||
}
|
||||
if(typeof foundValue !== "string"){
|
||||
if(foundValue === true && (this.value === "true" || this.value === "yes" )){
|
||||
if (typeof foundValue !== "string") {
|
||||
if (foundValue === true && (this.value === "true" || this.value === "yes")) {
|
||||
return true
|
||||
}
|
||||
if(foundValue === false && (this.value === "false" || this.value === "no" )){
|
||||
if (foundValue === false && (this.value === "false" || this.value === "no")) {
|
||||
return true
|
||||
}
|
||||
foundValue = ""+foundValue
|
||||
foundValue = "" + foundValue
|
||||
}
|
||||
return foundValue === this.value
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ export class TagUtils {
|
|||
]
|
||||
|
||||
static KVtoProperties(tags: Tag[]): Record<string, string> {
|
||||
const properties : Record<string, string> = {}
|
||||
const properties: Record<string, string> = {}
|
||||
for (const tag of tags) {
|
||||
properties[tag.key] = tag.value
|
||||
}
|
||||
|
|
|
@ -416,7 +416,7 @@ class MappedStore<TIn, T> extends Store<T> {
|
|||
this._upstreamPingCount = upstreamListenerHandler?.pingCount
|
||||
this._extraStores = extraStores
|
||||
this.registerCallbacksToUpstream()
|
||||
if(onDestroy !== undefined){
|
||||
if (onDestroy !== undefined) {
|
||||
onDestroy(() => this.unregisterFromUpstream())
|
||||
}
|
||||
}
|
||||
|
@ -698,7 +698,11 @@ export class UIEventSource<T> extends Store<T> implements Writable<T> {
|
|||
* srcSeen // => 21
|
||||
* lastSeen // => 42
|
||||
*/
|
||||
public map<J>(f: (t: T) => J, extraSources: Store<any>[] = [], onDestroy?: (f : () => void ) => void): Store<J> {
|
||||
public map<J>(
|
||||
f: (t: T) => J,
|
||||
extraSources: Store<any>[] = [],
|
||||
onDestroy?: (f: () => void) => void
|
||||
): Store<J> {
|
||||
return new MappedStore(this, f, extraSources, this._callbacks, f(this.data), onDestroy)
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -76,7 +76,8 @@ export default class FeatureReviews {
|
|||
) {
|
||||
const centerLonLat = GeoOperations.centerpointCoordinates(feature)
|
||||
;[this._lon, this._lat] = centerLonLat
|
||||
this._identity = mangroveIdentity ?? new MangroveIdentity(new UIEventSource<string>(undefined))
|
||||
this._identity =
|
||||
mangroveIdentity ?? new MangroveIdentity(new UIEventSource<string>(undefined))
|
||||
const nameKey = options?.nameKey ?? "name"
|
||||
|
||||
if (feature.geometry.type === "Point") {
|
||||
|
@ -103,7 +104,7 @@ export default class FeatureReviews {
|
|||
|
||||
this._uncertainty = options?.uncertaintyRadius ?? maxDistance
|
||||
}
|
||||
this._name = tagsSource .map((tags) => tags[nameKey] ?? options?.fallbackName)
|
||||
this._name = tagsSource.map((tags) => tags[nameKey] ?? options?.fallbackName)
|
||||
|
||||
this.subjectUri = this.ConstructSubjectUri()
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import ThemeViewState from "../../Models/ThemeViewState";
|
||||
import Hash from "./Hash";
|
||||
import ThemeViewState from "../../Models/ThemeViewState"
|
||||
import Hash from "./Hash"
|
||||
|
||||
export default class ThemeViewStateHashActor {
|
||||
private readonly _state: ThemeViewState;
|
||||
private readonly _state: ThemeViewState
|
||||
|
||||
/**
|
||||
* Converts the hash to the appropriate themeview state and, vice versa, sets the hash.
|
||||
|
@ -15,27 +15,27 @@ export default class ThemeViewStateHashActor {
|
|||
* @param state
|
||||
*/
|
||||
constructor(state: ThemeViewState) {
|
||||
this._state = state;
|
||||
this._state = state
|
||||
|
||||
// First of all, try to recover the selected element
|
||||
if (Hash.hash.data) {
|
||||
const hash = Hash.hash.data
|
||||
this.loadStateFromHash(hash)
|
||||
Hash.hash.setData(hash) // reapply the previous hash
|
||||
state.indexedFeatures.featuresById.addCallbackAndRunD(_ => {
|
||||
let unregister = this.loadSelectedElementFromHash(hash);
|
||||
state.indexedFeatures.featuresById.addCallbackAndRunD((_) => {
|
||||
let unregister = this.loadSelectedElementFromHash(hash)
|
||||
// once that we have found a matching element, we can be sure the indexedFeaturesource was popuplated and that the job is done
|
||||
return unregister
|
||||
})
|
||||
}
|
||||
|
||||
// Register a hash change listener to correctly handle the back button
|
||||
Hash.hash.addCallback(hash => {
|
||||
Hash.hash.addCallback((hash) => {
|
||||
if (!!hash) {
|
||||
// There is still a hash
|
||||
// We _only_ have to (at most) close the overlays in this case
|
||||
const parts = hash.split(";")
|
||||
if(parts.indexOf("background") < 0){
|
||||
if (parts.indexOf("background") < 0) {
|
||||
state.guistate.backgroundLayerSelectionIsOpened.setData(false)
|
||||
}
|
||||
this.loadSelectedElementFromHash(hash)
|
||||
|
@ -46,16 +46,14 @@ export default class ThemeViewStateHashActor {
|
|||
|
||||
// At last, register callbacks on the state to update the hash when they change.
|
||||
// Note: these should use 'addCallback', not 'addCallbackAndRun'
|
||||
state.selectedElement.addCallback(_ => this.setHash())
|
||||
state.guistate.allToggles.forEach(({toggle, submenu}) => {
|
||||
submenu?.addCallback(_ => this.setHash())
|
||||
toggle.addCallback(_ => this.setHash());
|
||||
state.selectedElement.addCallback((_) => this.setHash())
|
||||
state.guistate.allToggles.forEach(({ toggle, submenu }) => {
|
||||
submenu?.addCallback((_) => this.setHash())
|
||||
toggle.addCallback((_) => this.setHash())
|
||||
})
|
||||
|
||||
// When all is done, set the hash. This must happen last to give the code above correct info
|
||||
this.setHash()
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,8 +101,7 @@ export default class ThemeViewStateHashActor {
|
|||
private loadStateFromHash(hash: string) {
|
||||
const state = this._state
|
||||
const parts = hash.split(";")
|
||||
outer: for (const {toggle, name, showOverOthers, submenu} of state.guistate.allToggles) {
|
||||
|
||||
outer: for (const { toggle, name, showOverOthers, submenu } of state.guistate.allToggles) {
|
||||
for (const part of parts) {
|
||||
if (part === name) {
|
||||
toggle.setData(true)
|
||||
|
@ -125,17 +122,15 @@ export default class ThemeViewStateHashActor {
|
|||
// If we arrive here, the loop above has not found any match
|
||||
toggle.setData(false)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private setHash() {
|
||||
const s = this._state
|
||||
let h = ""
|
||||
|
||||
for (const {toggle, showOverOthers, name, submenu} of s.guistate.allToggles) {
|
||||
for (const { toggle, showOverOthers, name, submenu } of s.guistate.allToggles) {
|
||||
if (showOverOthers || !toggle.data) {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
h = name
|
||||
if (submenu?.data) {
|
||||
|
@ -147,9 +142,9 @@ export default class ThemeViewStateHashActor {
|
|||
h = s.selectedElement.data.properties.id
|
||||
}
|
||||
|
||||
for (const {toggle, showOverOthers, name, submenu} of s.guistate.allToggles) {
|
||||
for (const { toggle, showOverOthers, name, submenu } of s.guistate.allToggles) {
|
||||
if (!showOverOthers || !toggle.data) {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
if (h) {
|
||||
h += ";" + name
|
||||
|
@ -161,7 +156,6 @@ export default class ThemeViewStateHashActor {
|
|||
}
|
||||
}
|
||||
Hash.hash.setData(h)
|
||||
|
||||
}
|
||||
|
||||
private back() {
|
||||
|
@ -176,5 +170,4 @@ export default class ThemeViewStateHashActor {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue