More cleanup, first somewhat working version of #171
This commit is contained in:
parent
1f93923820
commit
bef684aec7
19 changed files with 439 additions and 135 deletions
|
@ -230,7 +230,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
navigator?.permissions
|
||||
?.query({name: "geolocation"})
|
||||
?.then(function (status) {
|
||||
console.log("Geolocation is already", status);
|
||||
console.log("Geolocation permission is ", status.state);
|
||||
if (status.state === "granted") {
|
||||
self.StartGeolocating(forceZoom);
|
||||
}
|
||||
|
@ -289,7 +289,6 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
|
||||
private StartGeolocating(zoomToGPS = true) {
|
||||
const self = this;
|
||||
console.log("Starting geolocation");
|
||||
|
||||
this._lastUserRequest = zoomToGPS ? new Date() : new Date(0);
|
||||
if (self._permission.data === "denied") {
|
||||
|
@ -301,8 +300,6 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
this.MoveToCurrentLoction(16);
|
||||
}
|
||||
|
||||
console.log("Searching location using GPS");
|
||||
|
||||
if (self._isActive.data) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -184,8 +184,8 @@ export default class OverpassFeatureSource implements FeatureSource, FeatureSour
|
|||
return;
|
||||
}
|
||||
this.runningQuery.setData(true);
|
||||
overpass.queryGeoJson(queryBounds,
|
||||
function (data, date) {
|
||||
overpass.queryGeoJson(queryBounds).
|
||||
then(([data, date]) => {
|
||||
self._previousBounds.get(z).push(queryBounds);
|
||||
self.retries.setData(0);
|
||||
const features = data.features.map(f => ({feature: f, freshness: date}));
|
||||
|
@ -197,12 +197,12 @@ export default class OverpassFeatureSource implements FeatureSource, FeatureSour
|
|||
console.error("Got the overpass response, but could not process it: ", e, e.stack)
|
||||
}
|
||||
self.runningQuery.setData(false);
|
||||
},
|
||||
function (reason) {
|
||||
})
|
||||
.catch((reason) => {
|
||||
self.retries.data++;
|
||||
self.ForceRefresh();
|
||||
self.timeout.setData(self.retries.data * 5);
|
||||
console.error(`QUERY FAILED (retrying in ${5 * self.retries.data} sec) due to ${reason}`);
|
||||
console.error(`QUERY FAILED (retrying in ${5 * self.retries.data} sec) due to`, reason);
|
||||
self.retries.ping();
|
||||
self.runningQuery.setData(false);
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@ export default class TitleHandler {
|
|||
constructor(state) {
|
||||
const currentTitle: UIEventSource<string> = state.selectedElement.map(
|
||||
selected => {
|
||||
console.log("UPdating title")
|
||||
|
||||
const layout = state.layoutToUse.data
|
||||
const defaultTitle = Translations.WT(layout?.title)?.txt ?? "MapComplete"
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import {BBox} from "../GeoOperations";
|
|||
import {TileHierarchyMerger} from "./TiledFeatureSource/TileHierarchyMerger";
|
||||
import RelationsTracker from "../Osm/RelationsTracker";
|
||||
import {NewGeometryFromChangesFeatureSource} from "./Sources/NewGeometryFromChangesFeatureSource";
|
||||
import ChangeGeometryApplicator from "./ChangeApplicator";
|
||||
import ChangeGeometryApplicator from "./Sources/ChangeGeometryApplicator";
|
||||
|
||||
|
||||
export default class FeaturePipeline implements FeatureSourceState {
|
||||
|
@ -159,7 +159,6 @@ export default class FeaturePipeline implements FeatureSourceState {
|
|||
|
||||
// Whenever fresh data comes in, we need to update the metatagging
|
||||
self.newDataLoadedSignal.stabilized(1000).addCallback(src => {
|
||||
console.log("Got an update from ", src.name)
|
||||
self.updateAllMetaTagging()
|
||||
})
|
||||
|
||||
|
@ -183,7 +182,6 @@ export default class FeaturePipeline implements FeatureSourceState {
|
|||
}
|
||||
|
||||
private updateAllMetaTagging() {
|
||||
console.log("Updating the meta tagging")
|
||||
const self = this;
|
||||
this.perLayerHierarchy.forEach(hierarchy => {
|
||||
hierarchy.loadedTiles.forEach(src => {
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
import FeatureSource, {FeatureSourceForLayer, IndexedFeatureSource} from "./FeatureSource";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import {Changes} from "../Osm/Changes";
|
||||
import {ChangeDescription, ChangeDescriptionTools} from "../Osm/Actions/ChangeDescription";
|
||||
import {Utils} from "../../Utils";
|
||||
import FilteredLayer from "../../Models/FilteredLayer";
|
||||
import {OsmNode, OsmRelation, OsmWay} from "../Osm/OsmObject";
|
||||
|
||||
|
||||
/**
|
||||
* Applies geometry changes from 'Changes' onto every feature of a featureSource
|
||||
*/
|
||||
import {Changes} from "../../Osm/Changes";
|
||||
import {UIEventSource} from "../../UIEventSource";
|
||||
import {FeatureSourceForLayer, IndexedFeatureSource} from "../FeatureSource";
|
||||
import FilteredLayer from "../../../Models/FilteredLayer";
|
||||
import {ChangeDescription, ChangeDescriptionTools} from "../../Osm/Actions/ChangeDescription";
|
||||
|
||||
|
||||
export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
||||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
|
||||
public readonly name: string;
|
||||
|
@ -76,6 +74,7 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
|||
// We only apply the last change as that one'll have the latest geometry
|
||||
const change = changesForFeature[changesForFeature.length - 1]
|
||||
copy.feature.geometry = ChangeDescriptionTools.getGeojsonGeometry(change)
|
||||
console.log("Applying a geometry change onto ", feature, change, copy)
|
||||
newFeatures.push(copy)
|
||||
}
|
||||
this.features.setData(newFeatures)
|
|
@ -27,7 +27,7 @@ export default class TiledFromLocalStorageSource implements TileHierarchy<Featur
|
|||
return Number(key.substring(prefix.length));
|
||||
})
|
||||
|
||||
console.log("Avaible datasets in local storage:", indexes)
|
||||
console.log("Layer", layer.layerDef.id, "has following tiles in available in localstorage", indexes.map(i => Utils.tile_from_index(i).join("/")).join(", "))
|
||||
|
||||
const zLevels = indexes.map(i => i % 100)
|
||||
const indexesSet = new Set(indexes)
|
||||
|
|
|
@ -15,13 +15,15 @@ export interface RelationSplitInput {
|
|||
* When a way is split and this way is part of a relation, the relation should be updated too to have the new segment if relevant.
|
||||
*/
|
||||
export default class RelationSplitHandler extends OsmChangeAction {
|
||||
private readonly _input: RelationSplitInput;
|
||||
|
||||
constructor(input: RelationSplitInput) {
|
||||
super()
|
||||
this._input = input;
|
||||
}
|
||||
|
||||
async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
|
||||
return [];
|
||||
return new InPlaceReplacedmentRTSH(this._input).CreateChangeDescriptions(changes)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,11 @@ export default class SplitAction extends OsmChangeAction {
|
|||
private readonly wayId: string;
|
||||
private readonly _splitPointsCoordinates: [number, number] []// lon, lat
|
||||
|
||||
/**
|
||||
*
|
||||
* @param wayId
|
||||
* @param splitPointCoordinates: lon, lat
|
||||
*/
|
||||
constructor(wayId: string, splitPointCoordinates: [number, number][]) {
|
||||
super()
|
||||
this.wayId = wayId;
|
||||
|
@ -39,12 +44,11 @@ export default class SplitAction extends OsmChangeAction {
|
|||
}
|
||||
|
||||
async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
|
||||
const self = this;
|
||||
const originalElement = <OsmWay>await OsmObject.DownloadObjectAsync(this.wayId)
|
||||
const originalElement = <OsmWay> await OsmObject.DownloadObjectAsync(this.wayId)
|
||||
const originalNodes = originalElement.nodes;
|
||||
|
||||
// First, calculate splitpoints and remove points close to one another
|
||||
const splitInfo = self.CalculateSplitCoordinates(originalElement)
|
||||
const splitInfo = this.CalculateSplitCoordinates(originalElement)
|
||||
// Now we have a list with e.g.
|
||||
// [ { originalIndex: 0}, {originalIndex: 1, doSplit: true}, {originalIndex: 2}, {originalIndex: undefined, doSplit: true}, {originalIndex: 3}]
|
||||
|
||||
|
@ -166,8 +170,9 @@ export default class SplitAction extends OsmChangeAction {
|
|||
private CalculateSplitCoordinates(osmWay: OsmWay, toleranceInM = 5): SplitInfo[] {
|
||||
const wayGeoJson = osmWay.asGeoJson()
|
||||
// Should be [lon, lat][]
|
||||
const originalPoints = osmWay.coordinates.map(c => <[number, number]>c.reverse())
|
||||
const originalPoints : [number, number][] = osmWay.coordinates.map(c => [c[1], c[0]])
|
||||
const allPoints: {
|
||||
// lon, lat
|
||||
coordinates: [number, number],
|
||||
isSplitPoint: boolean,
|
||||
originalIndex?: number, // Original index
|
||||
|
@ -180,6 +185,7 @@ export default class SplitAction extends OsmChangeAction {
|
|||
// - `dist`: distance between pt and the closest point,
|
||||
// `location`: distance along the line between start and the closest point.
|
||||
let projected = GeoOperations.nearestPoint(wayGeoJson, c)
|
||||
// c is lon lat
|
||||
return ({
|
||||
coordinates: c,
|
||||
isSplitPoint: true,
|
||||
|
@ -233,8 +239,12 @@ export default class SplitAction extends OsmChangeAction {
|
|||
if (distToNext > distToPrev) {
|
||||
closest = prevPoint
|
||||
}
|
||||
|
||||
// Ok, we have a closest point!
|
||||
|
||||
if(closest.originalIndex === 0 || closest.originalIndex === originalPoints.length){
|
||||
// We can not split on the first or last points...
|
||||
continue
|
||||
}
|
||||
closest.isSplitPoint = true;
|
||||
allPoints.splice(i, 1)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import {LocalStorageSource} from "../Web/LocalStorageSource";
|
|||
export class Changes {
|
||||
|
||||
|
||||
private static _nextId = -1; // Newly assigned ID's are negative
|
||||
private _nextId : number = -1; // Newly assigned ID's are negative
|
||||
public readonly name = "Newly added features"
|
||||
/**
|
||||
* All the newly created features as featureSource + all the modified features
|
||||
|
@ -30,6 +30,8 @@ export class Changes {
|
|||
constructor() {
|
||||
// We keep track of all changes just as well
|
||||
this.allChanges.setData([...this.pendingChanges.data])
|
||||
// If a pending change contains a negative ID, we save that
|
||||
this._nextId = Math.min(-1, ...this.pendingChanges.data?.map(pch => pch.id) ?? [])
|
||||
}
|
||||
|
||||
private static createChangesetFor(csId: string,
|
||||
|
@ -77,7 +79,7 @@ export class Changes {
|
|||
* Returns a new ID and updates the value for the next ID
|
||||
*/
|
||||
public getNewID() {
|
||||
return Changes._nextId--;
|
||||
return this._nextId--;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -63,17 +63,26 @@ export abstract class OsmObject {
|
|||
if (idN < 0) {
|
||||
return undefined;
|
||||
}
|
||||
switch (type) {
|
||||
case("node"):
|
||||
return await new OsmNode(idN).Download();
|
||||
case("way"):
|
||||
return await new OsmWay(idN).Download();
|
||||
case("relation"):
|
||||
return await new OsmRelation(idN).Download();
|
||||
default:
|
||||
throw ("Invalid object type:" + type + id);
|
||||
|
||||
const full = !id.startsWith("way") ? "" : "/full";
|
||||
const url = `${OsmObject.backendURL}api/0.6/${id}${full}`;
|
||||
const rawData = await Utils.downloadJson(url)
|
||||
// A full query might contain more then just the requested object (e.g. nodes that are part of a way, where we only want the way)
|
||||
const parsed = OsmObject.ParseObjects(rawData.elements);
|
||||
// Lets fetch the object we need
|
||||
for (const osmObject of parsed) {
|
||||
if(osmObject.type !== type){
|
||||
continue;
|
||||
}
|
||||
if(osmObject.id !== idN){
|
||||
continue
|
||||
}
|
||||
// Found the one!
|
||||
return osmObject
|
||||
}
|
||||
throw "PANIC: requested object is not part of the response"
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -205,6 +214,7 @@ export abstract class OsmObject {
|
|||
private static ParseObjects(elements: any[]): OsmObject[] {
|
||||
const objects: OsmObject[] = [];
|
||||
const allNodes: Map<number, OsmNode> = new Map<number, OsmNode>()
|
||||
|
||||
for (const element of elements) {
|
||||
const type = element.type;
|
||||
const idN = element.id;
|
||||
|
@ -226,6 +236,11 @@ export abstract class OsmObject {
|
|||
osmObject.SaveExtraData(element, [])
|
||||
break;
|
||||
}
|
||||
|
||||
if (osmObject !== undefined && OsmObject.backendURL !== OsmObject.defaultBackend) {
|
||||
osmObject.tags["_backend"] = OsmObject.backendURL
|
||||
}
|
||||
|
||||
osmObject?.LoadData(element)
|
||||
objects.push(osmObject)
|
||||
}
|
||||
|
@ -237,7 +252,7 @@ export abstract class OsmObject {
|
|||
|
||||
public abstract asGeoJson(): any;
|
||||
|
||||
abstract SaveExtraData(element: any, allElements: any[]);
|
||||
abstract SaveExtraData(element: any, allElements: OsmObject[]);
|
||||
|
||||
/**
|
||||
* Generates the changeset-XML for tags
|
||||
|
@ -260,37 +275,6 @@ export abstract class OsmObject {
|
|||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the object, a full download for ways and relations
|
||||
* @constructor
|
||||
*/
|
||||
async Download(): Promise<OsmObject> {
|
||||
const self = this;
|
||||
const full = this.type !== "way" ? "" : "/full";
|
||||
const url = `${OsmObject.backendURL}api/0.6/${this.type}/${this.id}${full}`;
|
||||
return await Utils.downloadJson(url).then(data => {
|
||||
const element = data.elements.pop();
|
||||
let nodes = []
|
||||
if (self.type === "way" && data.elements.length >= 0) {
|
||||
nodes = OsmObject.ParseObjects(data.elements)
|
||||
}
|
||||
|
||||
if (self.type === "rellation") {
|
||||
throw "We should save some extra data"
|
||||
}
|
||||
|
||||
self.LoadData(element)
|
||||
self.SaveExtraData(element, nodes);
|
||||
|
||||
if (OsmObject.backendURL !== OsmObject.defaultBackend) {
|
||||
self.tags["_backend"] = OsmObject.backendURL
|
||||
}
|
||||
return this;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
abstract ChangesetXML(changesetId: string): string;
|
||||
|
||||
protected VersionXML() {
|
||||
|
@ -363,7 +347,7 @@ export class OsmNode extends OsmObject {
|
|||
|
||||
export class OsmWay extends OsmObject {
|
||||
|
||||
nodes: number[];
|
||||
nodes: number[] = [];
|
||||
// The coordinates of the way, [lat, lon][]
|
||||
coordinates: [number, number][] = []
|
||||
lat: number;
|
||||
|
@ -400,6 +384,10 @@ export class OsmWay extends OsmObject {
|
|||
nodeDict.set(node.id, node)
|
||||
}
|
||||
|
||||
if (element.nodes === undefined) {
|
||||
console.log("PANIC")
|
||||
}
|
||||
|
||||
for (const nodeId of element.nodes) {
|
||||
const node = nodeDict.get(nodeId)
|
||||
if (node === undefined) {
|
||||
|
@ -419,8 +407,8 @@ export class OsmWay extends OsmObject {
|
|||
}
|
||||
|
||||
public asGeoJson() {
|
||||
let coordinates : ([number, number][] | [number, number][][]) = this.coordinates.map(c => <[number, number]>c.reverse());
|
||||
if(this.isPolygon()){
|
||||
let coordinates: ([number, number][] | [number, number][][]) = this.coordinates.map(c => [c[1], c[0]]);
|
||||
if (this.isPolygon()) {
|
||||
coordinates = [coordinates]
|
||||
}
|
||||
return {
|
||||
|
|
|
@ -145,14 +145,14 @@ export class OsmPreferences {
|
|||
|
||||
private SetPreference(k: string, v: string) {
|
||||
if (!this.userDetails.data.loggedIn) {
|
||||
console.log(`Not saving preference ${k}: user not logged in`);
|
||||
console.debug(`Not saving preference ${k}: user not logged in`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.preferences.data[k] === v) {
|
||||
return;
|
||||
}
|
||||
console.log("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15));
|
||||
console.debug("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15));
|
||||
|
||||
if (v === undefined || v === "") {
|
||||
this.auth.xhr({
|
||||
|
@ -161,10 +161,10 @@ export class OsmPreferences {
|
|||
options: {header: {'Content-Type': 'text/plain'}},
|
||||
}, function (error) {
|
||||
if (error) {
|
||||
console.log("Could not remove preference", error);
|
||||
console.warn("Could not remove preference", error);
|
||||
return;
|
||||
}
|
||||
console.log("Preference ", k, "removed!");
|
||||
console.debug("Preference ", k, "removed!");
|
||||
|
||||
});
|
||||
return;
|
||||
|
|
|
@ -31,7 +31,7 @@ export class Overpass {
|
|||
this._relationTracker = relationTracker
|
||||
}
|
||||
|
||||
queryGeoJson(bounds: Bounds, continuation: ((any, date: Date) => void), onFail: ((reason) => void)): void {
|
||||
public async queryGeoJson(bounds: Bounds): Promise<[any, Date]> {
|
||||
|
||||
let query = this.buildQuery("[bbox:" + bounds.south + "," + bounds.west + "," + bounds.north + "," + bounds.east + "]")
|
||||
|
||||
|
@ -40,24 +40,18 @@ export class Overpass {
|
|||
query = Overpass.testUrl;
|
||||
}
|
||||
const self = this;
|
||||
Utils.downloadJson(query)
|
||||
.then(json => {
|
||||
if (json.elements === [] && ((json.remarks ?? json.remark).indexOf("runtime error") >= 0)) {
|
||||
console.log("Timeout or other runtime error");
|
||||
onFail("Runtime error (timeout)")
|
||||
return;
|
||||
}
|
||||
const json = await Utils.downloadJson(query)
|
||||
|
||||
if (json.elements === [] && ((json.remarks ?? json.remark).indexOf("runtime error") >= 0)) {
|
||||
console.log("Timeout or other runtime error");
|
||||
throw("Runtime error (timeout)")
|
||||
}
|
||||
|
||||
|
||||
self._relationTracker.RegisterRelations(json)
|
||||
// @ts-ignore
|
||||
const geojson = OsmToGeoJson.default(json);
|
||||
const osmTime = new Date(json.osm3s.timestamp_osm_base);
|
||||
|
||||
continuation(geojson, osmTime);
|
||||
}).catch(e => {
|
||||
onFail(e);
|
||||
})
|
||||
self._relationTracker.RegisterRelations(json)
|
||||
// @ts-ignore
|
||||
const geojson = OsmToGeoJson.default(json);
|
||||
const osmTime = new Date(json.osm3s.timestamp_osm_base);
|
||||
return [geojson, osmTime];
|
||||
}
|
||||
|
||||
buildQuery(bbox: string): string {
|
||||
|
|
|
@ -100,7 +100,7 @@ export interface LayoutConfigJson {
|
|||
* However, users tend to pan and zoom a lot. It is pretty annoying if every single pan means a reloading of the data.
|
||||
* For this, the bounds are widened in order to make a small pan still within bounds of the loaded data.
|
||||
*
|
||||
* IF widenfactor is 0, this feature is disabled. A recommended value is between 0.5 and 0.01 (the latter for very dense queries)
|
||||
* IF widenfactor is 1, this feature is disabled. A recommended value is between 1 and 3
|
||||
*/
|
||||
widenFactor?: number;
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ export default class LayoutConfig {
|
|||
this.startZoom = json.startZoom;
|
||||
this.startLat = json.startLat;
|
||||
this.startLon = json.startLon;
|
||||
this.widenFactor = json.widenFactor ?? 0.05;
|
||||
this.widenFactor = json.widenFactor ?? 1.5;
|
||||
this.roamingRenderings = (json.roamingRenderings ?? []).map((tr, i) => {
|
||||
if (typeof tr === "string") {
|
||||
if (SharedTagRenderings.SharedTagRendering.get(tr) !== undefined) {
|
||||
|
|
62
Utils.ts
62
Utils.ts
|
@ -259,10 +259,10 @@ export class Utils {
|
|||
}
|
||||
|
||||
static tile_bounds_lon_lat(z: number, x: number, y: number): [[number, number], [number, number]] {
|
||||
return [[Utils.tile2long(x, z),Utils.tile2lat(y, z)], [Utils.tile2long(x + 1, z), Utils.tile2lat(y + 1, z)]]
|
||||
return [[Utils.tile2long(x, z), Utils.tile2lat(y, z)], [Utils.tile2long(x + 1, z), Utils.tile2lat(y + 1, z)]]
|
||||
}
|
||||
|
||||
static tile_index(z: number, x: number, y: number):number{
|
||||
|
||||
static tile_index(z: number, x: number, y: number): number {
|
||||
return ((x * (2 << z)) + y) * 100 + z
|
||||
}
|
||||
|
||||
|
@ -271,7 +271,7 @@ export class Utils {
|
|||
* @param index
|
||||
* @returns 'zxy'
|
||||
*/
|
||||
static tile_from_index(index: number) : [number, number, number]{
|
||||
static tile_from_index(index: number): [number, number, number] {
|
||||
const z = index % 100;
|
||||
const factor = 2 << z
|
||||
index = Math.floor(index / 100)
|
||||
|
@ -356,35 +356,43 @@ export class Utils {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static injectedDownloads = {}
|
||||
|
||||
public static injectJsonDownloadForTests(url: string, data) {
|
||||
Utils.injectedDownloads[url] = data
|
||||
}
|
||||
|
||||
public static downloadJson(url: string): Promise<any> {
|
||||
|
||||
const injected = Utils.injectedDownloads[url]
|
||||
if (injected !== undefined) {
|
||||
console.log("Using injected resource for test for URL", url)
|
||||
return new Promise((resolve, _) => resolve(injected))
|
||||
}
|
||||
|
||||
if (this.externalDownloadFunction !== undefined) {
|
||||
return this.externalDownloadFunction(url)
|
||||
}
|
||||
|
||||
return new Promise(
|
||||
(resolve, reject) => {
|
||||
try {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.onload = () => {
|
||||
if (xhr.status == 200) {
|
||||
try {
|
||||
resolve(JSON.parse(xhr.response))
|
||||
} catch (e) {
|
||||
reject("Not a valid json: " + xhr.response)
|
||||
}
|
||||
} else {
|
||||
reject(xhr.statusText)
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.onload = () => {
|
||||
if (xhr.status == 200) {
|
||||
try {
|
||||
console.log("Got a response! Parsing now...")
|
||||
resolve(JSON.parse(xhr.response))
|
||||
} catch (e) {
|
||||
reject("Not a valid json: " + xhr.response)
|
||||
}
|
||||
};
|
||||
xhr.open('GET', url);
|
||||
xhr.setRequestHeader("accept", "application/json")
|
||||
xhr.send();
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
} else {
|
||||
reject(xhr.statusText)
|
||||
}
|
||||
};
|
||||
xhr.open('GET', url);
|
||||
xhr.setRequestHeader("accept", "application/json")
|
||||
xhr.send();
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -486,12 +494,12 @@ export class Utils {
|
|||
}
|
||||
|
||||
static sortKeys(o: any) {
|
||||
const copy = {}
|
||||
const copy = {}
|
||||
let keys = Object.keys(o)
|
||||
keys = keys.sort()
|
||||
for (const key of keys) {
|
||||
let v = o[key]
|
||||
if(typeof v === "object"){
|
||||
if (typeof v === "object") {
|
||||
v = Utils.sortKeys(v)
|
||||
}
|
||||
copy[key] = v
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"startZoom": 14,
|
||||
"startLon": 3.2228,
|
||||
"maintainer": "MapComplete",
|
||||
"widenfactor": 0.01,
|
||||
"widenfactor": 2,
|
||||
"roamingRenderings": [
|
||||
{
|
||||
"question": {
|
||||
|
|
|
@ -3,6 +3,7 @@ import {InPlaceReplacedmentRTSH} from "../Logic/Osm/Actions/RelationSplitHandler
|
|||
import {OsmObject, OsmRelation} from "../Logic/Osm/OsmObject";
|
||||
import {Changes} from "../Logic/Osm/Changes";
|
||||
import {equal} from "assert";
|
||||
import {Utils} from "../Utils";
|
||||
|
||||
export default class RelationSplitHandlerSpec extends T {
|
||||
|
||||
|
@ -58,6 +59,28 @@ export default class RelationSplitHandlerSpec extends T {
|
|||
}
|
||||
|
||||
constructor() {
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/node/1124134958/ways",
|
||||
{"version":"0.6","generator":"CGImap 0.8.5 (2937646 spike-07.openstreetmap.org)","copyright":"OpenStreetMap and contributors","attribution":"http://www.openstreetmap.org/copyright","license":"http://opendatacommons.org/licenses/odbl/1-0/","elements":[{"type":"way","id":97038428,"timestamp":"2019-06-19T12:26:24Z","version":6,"changeset":71399984,"user":"Pieter Vander Vennet","uid":3818858,"nodes":[1124134958,323729212,323729351,2542460408,187073405],"tags":{"highway":"residential","name":"Brugs-Kerkhofstraat","sett:pattern":"arc","surface":"sett"}},{"type":"way","id":97038434,"timestamp":"2019-06-19T12:26:24Z","version":5,"changeset":71399984,"user":"Pieter Vander Vennet","uid":3818858,"nodes":[1124134958,1124135024,187058607],"tags":{"bicycle":"use_sidepath","highway":"residential","name":"Kerkhofblommenstraat","sett:pattern":"arc","surface":"sett"}},{"type":"way","id":97038435,"timestamp":"2017-12-21T21:41:08Z","version":4,"changeset":54826837,"user":"Jakka","uid":2403313,"nodes":[1124134958,2576628889,1124135035,5298371485,5298371495],"tags":{"bicycle":"use_sidepath","highway":"residential","name":"Kerkhofblommenstraat"}},{"type":"way","id":251446313,"timestamp":"2019-01-07T19:22:47Z","version":4,"changeset":66106872,"user":"M!dgard","uid":763799,"nodes":[1124134958,5243143198,4555715455],"tags":{"foot":"yes","highway":"service"}}]}
|
||||
)
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/relation/9572808",
|
||||
{"version":"0.6","generator":"CGImap 0.8.5 (3128319 spike-07.openstreetmap.org)","copyright":"OpenStreetMap and contributors","attribution":"http://www.openstreetmap.org/copyright","license":"http://opendatacommons.org/licenses/odbl/1-0/","elements":[{"type":"relation","id":9572808,"timestamp":"2021-08-12T12:44:06Z","version":11,"changeset":109573204,"user":"A67-A67","uid":553736,"members":[{"type":"way","ref":173662702,"role":""},{"type":"way","ref":467606230,"role":""},{"type":"way","ref":126267167,"role":""},{"type":"way","ref":301897426,"role":""},{"type":"way","ref":687866206,"role":""},{"type":"way","ref":295132739,"role":""},{"type":"way","ref":690497698,"role":""},{"type":"way","ref":627893684,"role":""},{"type":"way","ref":295132741,"role":""},{"type":"way","ref":301903120,"role":""},{"type":"way","ref":672541156,"role":""},{"type":"way","ref":126264330,"role":""},{"type":"way","ref":280440853,"role":""},{"type":"way","ref":838499667,"role":""},{"type":"way","ref":838499663,"role":""},{"type":"way","ref":690497623,"role":""},{"type":"way","ref":301902946,"role":""},{"type":"way","ref":280460715,"role":""},{"type":"way","ref":972534369,"role":""},{"type":"way","ref":695680702,"role":""},{"type":"way","ref":690497860,"role":""},{"type":"way","ref":295410363,"role":""},{"type":"way","ref":823864063,"role":""},{"type":"way","ref":663172088,"role":""},{"type":"way","ref":659950322,"role":""},{"type":"way","ref":659950323,"role":""},{"type":"way","ref":230180094,"role":""},{"type":"way","ref":690497912,"role":""},{"type":"way","ref":39588765,"role":""}],"tags":{"distance":"13 km","name":"Abdijenroute","network":"lcn","old_name":"Spoorlijn 58","operator":"Toerisme West-Vlaanderen","railway":"abandoned","route":"bicycle","type":"route","wikipedia":"nl:Spoorlijn 58"}}]}
|
||||
)
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/way/687866206/full",
|
||||
{"version":"0.6","generator":"CGImap 0.8.5 (2601512 spike-07.openstreetmap.org)","copyright":"OpenStreetMap and contributors","attribution":"http://www.openstreetmap.org/copyright","license":"http://opendatacommons.org/licenses/odbl/1-0/","elements":[{"type":"node","id":5273988959,"lat":51.1811406,"lon":3.2427712,"timestamp":"2021-07-29T21:14:53Z","version":6,"changeset":108847202,"user":"kaart_fietser","uid":11022240,"tags":{"network:type":"node_network","rwn_ref":"32"}},{"type":"node","id":6448669326,"lat":51.1811346,"lon":3.242891,"timestamp":"2019-05-04T22:44:12Z","version":1,"changeset":69891295,"user":"Pieter Vander Vennet","uid":3818858,"tags":{"barrier":"bollard"}},{"type":"way","id":687866206,"timestamp":"2019-05-06T20:52:20Z","version":2,"changeset":69951497,"user":"noelbov","uid":8054928,"nodes":[6448669326,5273988959],"tags":{"highway":"cycleway","name":"Abdijenroute","railway":"abandoned","surface":"asphalt"}}]}
|
||||
)
|
||||
|
||||
Utils.injectJsonDownloadForTests(
|
||||
"https://www.openstreetmap.org/api/0.6/way/690497698/full" ,
|
||||
{"version":"0.6","generator":"CGImap 0.8.5 (3023311 spike-07.openstreetmap.org)","copyright":"OpenStreetMap and contributors","attribution":"http://www.openstreetmap.org/copyright","license":"http://opendatacommons.org/licenses/odbl/1-0/","elements":[{"type":"node","id":170497152,"lat":51.1832353,"lon":3.2498759,"timestamp":"2018-04-24T00:29:37Z","version":7,"changeset":58357376,"user":"Pieter Vander Vennet","uid":3818858},{"type":"node","id":2988218625,"lat":51.1835053,"lon":3.2503067,"timestamp":"2018-09-24T21:48:46Z","version":2,"changeset":62895918,"user":"A67-A67","uid":553736},{"type":"node","id":5273988967,"lat":51.182659,"lon":3.249004,"timestamp":"2017-12-09T18:40:21Z","version":1,"changeset":54493533,"user":"CacherB","uid":1999108},{"type":"way","id":690497698,"timestamp":"2021-07-29T21:14:53Z","version":3,"changeset":108847202,"user":"kaart_fietser","uid":11022240,"nodes":[2988218625,170497152,5273988967],"tags":{"highway":"cycleway","lit":"no","name":"Abdijenroute","oneway":"no","railway":"abandoned","surface":"compacted"}}]}
|
||||
)
|
||||
|
||||
|
||||
super("relationsplithandler", [
|
||||
["split 295132739",
|
||||
() => RelationSplitHandlerSpec.split().then(_ => console.log("OK"))]
|
||||
|
|
274
test/SplitAction.spec.ts
Normal file
274
test/SplitAction.spec.ts
Normal file
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,8 @@ import OsmObjectSpec from "./OsmObject.spec";
|
|||
import ScriptUtils from "../scripts/ScriptUtils";
|
||||
import UnitsSpec from "./Units.spec";
|
||||
import RelationSplitHandlerSpec from "./RelationSplitHandler.spec";
|
||||
|
||||
import SplitActionSpec from "./SplitAction.spec";
|
||||
import {Utils} from "../Utils";
|
||||
|
||||
|
||||
ScriptUtils.fixUtils()
|
||||
|
@ -21,9 +22,19 @@ const allTests = [
|
|||
new ThemeSpec(),
|
||||
new UtilsSpec(),
|
||||
new UnitsSpec(),
|
||||
new RelationSplitHandlerSpec()
|
||||
new RelationSplitHandlerSpec(),
|
||||
new SplitActionSpec()
|
||||
]
|
||||
|
||||
Utils.externalDownloadFunction = async (url) => {
|
||||
console.error("Fetching ", url, "blocked in tests, use Utils.injectJsonDownloadForTests")
|
||||
const data = await ScriptUtils.DownloadJSON(url)
|
||||
console.log("\n\n ----------- \nBLOCKED DATA\n Utils.injectJsonDownloadForTests(\n" +
|
||||
" ", JSON.stringify(url),", \n",
|
||||
" ", JSON.stringify(data), "\n )\n------------------\n\n")
|
||||
throw "Detected internet access for URL " + url + ", please inject it with Utils.injectJsonDownloadForTests"
|
||||
}
|
||||
|
||||
let args = [...process.argv]
|
||||
args.splice(0, 2)
|
||||
args = args.map(a => a.toLowerCase())
|
||||
|
@ -34,15 +45,15 @@ if (args.length > 0) {
|
|||
testsToRun = allTests.filter(t => args.indexOf(t.name) >= 0)
|
||||
}
|
||||
|
||||
if(testsToRun.length == 0){
|
||||
if (testsToRun.length == 0) {
|
||||
throw "No tests found"
|
||||
}
|
||||
|
||||
for (let i = 0; i < testsToRun.length; i++){
|
||||
for (let i = 0; i < testsToRun.length; i++) {
|
||||
const test = testsToRun[i];
|
||||
ScriptUtils.erasableLog(" Running test", i, "/", allTests.length)
|
||||
console.log(" Running test", i, "/", allTests.length, test.name)
|
||||
allFailures.push(...(test.Run() ?? []))
|
||||
|
||||
console.log("OK!")
|
||||
}
|
||||
if (allFailures.length > 0) {
|
||||
for (const failure of allFailures) {
|
||||
|
@ -50,4 +61,4 @@ if (allFailures.length > 0) {
|
|||
}
|
||||
throw "Some test failed"
|
||||
}
|
||||
console.log("All tests successful: ", allTests.map(t => t.name).join(", "))
|
||||
console.log("All tests successful: ", testsToRun.map(t => t.name).join(", "))
|
||||
|
|
Loading…
Reference in a new issue