diff --git a/Logic/Actors/ChangeToElementsActor.ts b/Logic/Actors/ChangeToElementsActor.ts index 2f157866ae..9ae5f87ef4 100644 --- a/Logic/Actors/ChangeToElementsActor.ts +++ b/Logic/Actors/ChangeToElementsActor.ts @@ -7,7 +7,7 @@ export default class ChangeToElementsActor { for (const change of changes) { const id = change.type + "/" + change.id; if (!allElements.has(id)) { -continue; // Will be picked up later on + continue; // Ignored as the geometryFixer will introduce this } const src = allElements.getEventSourceById(id) diff --git a/Logic/Actors/SelectedFeatureHandler.ts b/Logic/Actors/SelectedFeatureHandler.ts index 3aa5d8e5bc..3cfaa079cf 100644 --- a/Logic/Actors/SelectedFeatureHandler.ts +++ b/Logic/Actors/SelectedFeatureHandler.ts @@ -13,7 +13,7 @@ export default class SelectedFeatureHandler { private readonly _hash: UIEventSource; private readonly _selectedFeature: UIEventSource; - private static readonly _no_trigger_on = ["welcome","copyright","layers"] + private static readonly _no_trigger_on = ["welcome","copyright","layers","new"] private readonly _osmApiSource: OsmApiFeatureSource; constructor(hash: UIEventSource, @@ -60,7 +60,9 @@ export default class SelectedFeatureHandler { if(hash === undefined || SelectedFeatureHandler._no_trigger_on.indexOf(hash) >= 0){ return; // No valid feature selected } - // We should have a valid osm-ID and zoom to it + // We should have a valid osm-ID and zoom to it... But we wrap it in try-catch to be sure + try{ + OsmObject.DownloadObject(hash).addCallbackAndRunD(element => { const centerpoint = element.centerpoint(); console.log("Zooming to location for select point: ", centerpoint) @@ -68,6 +70,9 @@ export default class SelectedFeatureHandler { location.data.lon = centerpoint[1] location.ping(); }) + }catch(e){ + console.error("Could not download OSM-object with id", hash, " - probably a weird hash") + } } private downloadFeature(hash: string){ diff --git a/Logic/FeatureSource/ChangeApplicator.ts b/Logic/FeatureSource/ChangeApplicator.ts index 58ba5174ce..e9aa7ac18f 100644 --- a/Logic/FeatureSource/ChangeApplicator.ts +++ b/Logic/FeatureSource/ChangeApplicator.ts @@ -5,6 +5,7 @@ import {ChangeDescription} from "../Osm/Actions/ChangeDescription"; import {Utils} from "../../Utils"; import {OsmNode, OsmRelation, OsmWay} from "../Osm/OsmObject"; + /** * Applies changes from 'Changes' onto a featureSource */ @@ -16,25 +17,41 @@ export default class ChangeApplicator implements FeatureSource { this.name = "ChangesApplied(" + source.name + ")" this.features = source.features - + const seenChanges = new Set(); + const self = this; + let runningUpdate = false; source.features.addCallbackAndRunD(features => { + if(runningUpdate){ + return; // No need to ping again + } ChangeApplicator.ApplyChanges(features, changes.pendingChanges.data) + seenChanges.clear() }) changes.pendingChanges.addCallbackAndRunD(changes => { - ChangeApplicator.ApplyChanges(source.features.data, changes) + runningUpdate = true; + changes = changes.filter(ch => !seenChanges.has(ch)) + changes.forEach(c => seenChanges.add(c)) + console.log("Called back", changes) + ChangeApplicator.ApplyChanges(self.features.data, changes) source.features.ping() + runningUpdate = false; }) } - private static ApplyChanges(features: { feature: any, freshness: Date }[], cs: ChangeDescription[]) { - if (cs.length === 0 || features === undefined) { - return features; + /** + * Returns true if the geometry is changed and the source should be pinged + */ + private static ApplyChanges(features: {feature: any, freshness: Date}[], cs: ChangeDescription[]): boolean { + if (cs.length === 0 || features === undefined ) { + return ; } + console.log("Applying changes ", this.name, cs) + let geometryChanged = false; const changesPerId: Map = new Map() for (const c of cs) { const id = c.type + "/" + c.id @@ -52,6 +69,8 @@ export default class ChangeApplicator implements FeatureSource { feature: feature, freshness: now }) + console.log("Added a new feature: ", feature) + geometryChanged = true; } // First, create the new features - they have a negative ID @@ -61,7 +80,11 @@ export default class ChangeApplicator implements FeatureSource { if (change.id >= 0) { return; // Nothing to do here, already created } - + + if(change.changes === undefined){ + // An update to the object - not the actual created + return; + } try { @@ -93,8 +116,8 @@ export default class ChangeApplicator implements FeatureSource { for (const feature of features) { - const id = feature.feature.properties.id; const f = feature.feature; + const id = f.properties.id; if (!changesPerId.has(id)) { continue; } @@ -118,11 +141,12 @@ export default class ChangeApplicator implements FeatureSource { // Apply other changes to the object if (change.changes !== undefined) { + geometryChanged = true; switch (change.type) { case "node": // @ts-ignore const coor: { lat, lon } = change.changes; - f.geometry.coordinates = [[coor.lon, coor.lat]] + f.geometry.coordinates = [coor.lon, coor.lat] break; case "way": f.geometry.coordinates = change.changes["locations"] @@ -134,5 +158,6 @@ export default class ChangeApplicator implements FeatureSource { } } } + return geometryChanged } } \ No newline at end of file diff --git a/Logic/FeatureSource/OsmApiFeatureSource.ts b/Logic/FeatureSource/OsmApiFeatureSource.ts index ec1c03a743..de90274d2a 100644 --- a/Logic/FeatureSource/OsmApiFeatureSource.ts +++ b/Logic/FeatureSource/OsmApiFeatureSource.ts @@ -15,15 +15,19 @@ export default class OsmApiFeatureSource implements FeatureSource { public load(id: string) { - if(id.indexOf("-") >= 0){ + if (id.indexOf("-") >= 0) { // Newly added point - not yet in OSM return; } console.debug("Downloading", id, "from the OSM-API") OsmObject.DownloadObject(id).addCallbackAndRunD(element => { - const geojson = element.asGeoJson(); - geojson.id = geojson.properties.id; - this.features.setData([{feature: geojson, freshness: element.timestamp}]) + try { + const geojson = element.asGeoJson(); + geojson.id = geojson.properties.id; + this.features.setData([{feature: geojson, freshness: element.timestamp}]) + } catch (e) { + console.error(e) + } }) } @@ -58,7 +62,7 @@ export default class OsmApiFeatureSource implements FeatureSource { const bounds = Utils.tile_bounds(z, x, y); console.log("Loading OSM data tile", z, x, y, " with bounds", bounds) OsmObject.LoadArea(bounds, objects => { - const keptGeoJson: {feature:any, freshness: Date}[] = [] + const keptGeoJson: { feature: any, freshness: Date }[] = [] // Which layer does the object match? for (const object of objects) { @@ -69,7 +73,7 @@ export default class OsmApiFeatureSource implements FeatureSource { if (doesMatch) { const geoJson = object.asGeoJson(); geoJson._matching_layer_id = layer.id - keptGeoJson.push({feature: geoJson, freshness: object.timestamp}) + keptGeoJson.push({feature: geoJson, freshness: object.timestamp}) break; } diff --git a/Logic/Osm/Actions/ChangeTagAction.ts b/Logic/Osm/Actions/ChangeTagAction.ts index 1915d18585..36bafcbeea 100644 --- a/Logic/Osm/Actions/ChangeTagAction.ts +++ b/Logic/Osm/Actions/ChangeTagAction.ts @@ -37,7 +37,7 @@ export default class ChangeTagAction extends OsmChangeAction { return {k: key.trim(), v: value.trim()}; } - Perform(changes: Changes): ChangeDescription [] { + CreateChangeDescriptions(changes: Changes): ChangeDescription [] { const changedTags: { k: string, v: string }[] = this._tagsFilter.asChange(this._currentTags).map(ChangeTagAction.checkChange) const typeId = this._elementId.split("/") const type = typeId[0] diff --git a/Logic/Osm/Actions/CreateNewNodeAction.ts b/Logic/Osm/Actions/CreateNewNodeAction.ts index 28a6560392..692271a126 100644 --- a/Logic/Osm/Actions/CreateNewNodeAction.ts +++ b/Logic/Osm/Actions/CreateNewNodeAction.ts @@ -4,23 +4,27 @@ import {Changes} from "../Changes"; import {ChangeDescription} from "./ChangeDescription"; import {And} from "../../Tags/And"; -export default class CreateNewNodeAction implements OsmChangeAction { +export default class CreateNewNodeAction extends OsmChangeAction { private readonly _basicTags: Tag[]; private readonly _lat: number; private readonly _lon: number; + public newElementId : string = undefined + constructor(basicTags: Tag[], lat: number, lon: number) { + super() this._basicTags = basicTags; this._lat = lat; this._lon = lon; } - Perform(changes: Changes): ChangeDescription[] { + CreateChangeDescriptions(changes: Changes): ChangeDescription[] { const id = changes.getNewID() const properties = { id: "node/" + id } + this.newElementId = "node/"+id for (const kv of this._basicTags) { if (typeof kv.value !== "string") { throw "Invalid value: don't use a regex in a preset" diff --git a/Logic/Osm/Actions/OsmChangeAction.ts b/Logic/Osm/Actions/OsmChangeAction.ts index ecb9f3df82..0308ca8f61 100644 --- a/Logic/Osm/Actions/OsmChangeAction.ts +++ b/Logic/Osm/Actions/OsmChangeAction.ts @@ -7,10 +7,17 @@ import {ChangeDescription} from "./ChangeDescription"; export default abstract class OsmChangeAction { + private isUsed = false + + public Perform(changes: Changes) { + if (this.isUsed) { + throw "This ChangeAction is already used: " + this.constructor.name + } + this.isUsed = true; + return this.CreateChangeDescriptions(changes) + } + + protected abstract CreateChangeDescriptions(changes: Changes): ChangeDescription[] - public abstract Perform(changes: Changes): ChangeDescription[] - - - } \ No newline at end of file diff --git a/Logic/Osm/Actions/RelationSplitlHandler.ts b/Logic/Osm/Actions/RelationSplitlHandler.ts index 601b2d1367..215cee8406 100644 --- a/Logic/Osm/Actions/RelationSplitlHandler.ts +++ b/Logic/Osm/Actions/RelationSplitlHandler.ts @@ -12,7 +12,7 @@ export default class RelationSplitlHandler extends OsmChangeAction{ super() } - Perform(changes: Changes): ChangeDescription[] { + CreateChangeDescriptions(changes: Changes): ChangeDescription[] { return []; } diff --git a/Logic/Osm/Actions/SplitAction.ts b/Logic/Osm/Actions/SplitAction.ts index c17fd3fde2..1e9f94adef 100644 --- a/Logic/Osm/Actions/SplitAction.ts +++ b/Logic/Osm/Actions/SplitAction.ts @@ -42,7 +42,7 @@ export default class SplitAction extends OsmChangeAction { return wayParts.filter(wp => wp.length > 0) } - Perform(changes: Changes): ChangeDescription[] { + CreateChangeDescriptions(changes: Changes): ChangeDescription[] { const splitPoints = this._splitPoints // We mark the new split points with a new id console.log(splitPoints) @@ -72,7 +72,6 @@ export default class SplitAction extends OsmChangeAction { // Next up is creating actual parts from this const wayParts: SplitInfo[][] = SplitAction.SegmentSplitInfo(splitInfo); -console.log("WayParts", wayParts, "by", splitInfo) // Allright! At this point, we have our new ways! // Which one is the longest of them (and can keep the id)? @@ -144,7 +143,7 @@ console.log("WayParts", wayParts, "by", splitInfo) // At last, we still have to check that we aren't part of a relation... // At least, the order of the ways is identical, so we can keep the same roles - changeDescription.push(...new RelationSplitlHandler(partOf, newWayIds, originalNodes).Perform(changes)) + changeDescription.push(...new RelationSplitlHandler(partOf, newWayIds, originalNodes).CreateChangeDescriptions(changes)) // And we have our objects! // Time to upload diff --git a/Logic/Osm/Changes.ts b/Logic/Osm/Changes.ts index 18b67970ea..4fb0f0892f 100644 --- a/Logic/Osm/Changes.ts +++ b/Logic/Osm/Changes.ts @@ -4,7 +4,6 @@ import {UIEventSource} from "../UIEventSource"; import Constants from "../../Models/Constants"; import OsmChangeAction from "./Actions/OsmChangeAction"; import {ChangeDescription} from "./Actions/ChangeDescription"; -import {LocalStorageSource} from "../Web/LocalStorageSource"; import {Utils} from "../../Utils"; /** @@ -23,25 +22,23 @@ export class Changes { public readonly pendingChanges = new UIEventSource([]) // LocalStorageSource.GetParsed("pending-changes", []) private readonly isUploading = new UIEventSource(false); + + private readonly previouslyCreated : OsmObject[] = [] constructor() { - this.isUploading.addCallbackAndRun(u => { - if (u) { - console.trace("Uploading set!") - } - }) + } - public static createChangesetFor(csId: string, + private static createChangesetFor(csId: string, allChanges: { - modifiedObjects?: OsmObject[], - newElements?: OsmObject[], - deletedElements?: OsmObject[] + modifiedObjects: OsmObject[], + newObjects: OsmObject[], + deletedObjects: OsmObject[] }): string { const changedElements = allChanges.modifiedObjects ?? [] - const newElements = allChanges.newElements ?? [] - const deletedElements = allChanges.deletedElements ?? [] + const newElements = allChanges.newObjects ?? [] + const deletedElements = allChanges.deletedObjects ?? [] let changes = ``; if (newElements.length > 0) { @@ -73,7 +70,7 @@ export class Changes { .map(c => c.type + "/" + c.id)) } - private static CreateChangesetObjects(changes: ChangeDescription[], downloadedOsmObjects: OsmObject[]): { + private CreateChangesetObjects(changes: ChangeDescription[], downloadedOsmObjects: OsmObject[]): { newObjects: OsmObject[], modifiedObjects: OsmObject[] deletedObjects: OsmObject[] @@ -87,12 +84,21 @@ export class Changes { states.set(o.type + "/" + o.id, "unchanged") } + for (const o of this.previouslyCreated) { + objects.set(o.type + "/" + o.id, o) + states.set(o.type + "/" + o.id, "unchanged") + } + let changed = false; for (const change of changes) { const id = change.type + "/" + change.id if (!objects.has(id)) { + if(change.id >= 0){ + throw "Did not get an object that should be known: "+id + } // This is a new object that should be created states.set(id, "created") + console.log("Creating object for changeDescription", change) let osmObj: OsmObject = undefined; switch (change.type) { case "node": @@ -116,6 +122,7 @@ export class Changes { throw "Hmm? This is a bug" } objects.set(id, osmObj) + this.previouslyCreated.push(osmObj) } const state = states.get(id) @@ -195,8 +202,8 @@ export class Changes { newObjects: [], modifiedObjects: [], deletedObjects: [] - } + objects.forEach((v, id) => { const state = states.get(id) @@ -228,20 +235,18 @@ export class Changes { */ public flushChanges(flushreason: string = undefined) { if (this.pendingChanges.data.length === 0) { - console.log("No pending changes") return; } - if (flushreason !== undefined) { - console.log(flushreason) - } - + if (this.isUploading.data) { - console.log("Is uploading... Abort") + console.log("Is already uploading... Abort") return; } + + this.isUploading.setData(true) - - console.log("Beginning upload..."); + + console.log("Beginning upload... "+flushreason ?? ""); // At last, we build the changeset and upload const self = this; const pending = self.pendingChanges.data; @@ -249,8 +254,12 @@ export class Changes { console.log("Needed ids", neededIds) OsmObject.DownloadAll(neededIds, true).addCallbackAndRunD(osmObjects => { console.log("Got the fresh objects!", osmObjects, "pending: ", pending) - const changes = Changes.CreateChangesetObjects(pending, osmObjects) - console.log("Changes", changes) + const changes: { + newObjects: OsmObject[], + modifiedObjects: OsmObject[] + deletedObjects: OsmObject[] + + } = self.CreateChangesetObjects(pending, osmObjects) if (changes.newObjects.length + changes.deletedObjects.length + changes.modifiedObjects.length === 0) { console.log("No changes to be made") this.pendingChanges.setData([]) @@ -262,11 +271,8 @@ export class Changes { State.state.osmConnection.UploadChangeset( State.state.layoutToUse.data, State.state.allElements, - (csId) => { - return Changes.createChangesetFor(csId, changes); - }, + (csId) => Changes.createChangesetFor(csId, changes), () => { - // When done console.log("Upload successfull!") self.pendingChanges.setData([]); self.isUploading.setData(false) diff --git a/Logic/Osm/OsmObject.ts b/Logic/Osm/OsmObject.ts index 70a93e9061..fcc3da8886 100644 --- a/Logic/Osm/OsmObject.ts +++ b/Logic/Osm/OsmObject.ts @@ -23,7 +23,7 @@ export abstract class OsmObject { this.id = id; this.type = type; this.tags = { - id: id + id: `${this.type}/${id}` } } @@ -52,6 +52,9 @@ export abstract class OsmObject { const splitted = id.split("/"); const type = splitted[0]; const idN = Number(splitted[1]); + if(idN <0){ + return; + } OsmObject.objectCache.set(id, src); const newContinuation = (element: OsmObject) => { @@ -69,7 +72,7 @@ export abstract class OsmObject { new OsmRelation(idN).Download(newContinuation); break; default: - throw "Invalid road type:" + type; + throw "Invalid object type:" + type + id; } return src; @@ -105,7 +108,7 @@ export abstract class OsmObject { if (OsmObject.referencingRelationsCache.has(id)) { return OsmObject.referencingRelationsCache.get(id); } - const relsSrc = new UIEventSource([]) + const relsSrc = new UIEventSource(undefined) OsmObject.referencingRelationsCache.set(id, relsSrc); Utils.downloadJson(`${OsmObject.backendURL}api/0.6/${id}/relations`) .then(data => { diff --git a/Logic/UIEventSource.ts b/Logic/UIEventSource.ts index b7b7629c96..84fa426b6b 100644 --- a/Logic/UIEventSource.ts +++ b/Logic/UIEventSource.ts @@ -6,7 +6,7 @@ export class UIEventSource { public data: T; public trace: boolean; private readonly tag: string; - private _callbacks = []; + private _callbacks: ((t: T) => (boolean | void | any)) [] = []; constructor(data: T, tag: string = "") { this.tag = tag; @@ -31,7 +31,7 @@ export class UIEventSource { } return []; } - + public static flatten(source: UIEventSource>, possibleSources: UIEventSource[]): UIEventSource { const sink = new UIEventSource(source.data?.data); @@ -63,7 +63,13 @@ export class UIEventSource { } - public addCallback(callback: ((latestData: T) => void)): UIEventSource { + /** + * Adds a callback + * + * If the result of the callback is 'true', the callback is considered finished and will be removed again + * @param callback + */ + public addCallback(callback: ((latestData: T) => (boolean | void | any))): UIEventSource { if (callback === console.log) { // This ^^^ actually works! throw "Don't add console.log directly as a callback - you'll won't be able to find it afterwards. Wrap it in a lambda instead." @@ -90,8 +96,21 @@ export class UIEventSource { } public ping(): void { + let toDelete = undefined for (const callback of this._callbacks) { - callback(this.data); + if (callback(this.data) === true) { + // This callback wants to be deleted + if (toDelete === undefined) { + toDelete = [callback] + } else { + toDelete.push(callback) + } + } + } + if (toDelete !== undefined) { + for (const toDeleteElement of toDelete) { + this._callbacks.splice(this._callbacks.indexOf(toDeleteElement), 1) + } } } diff --git a/State.ts b/State.ts index 629af8e06c..6885109491 100644 --- a/State.ts +++ b/State.ts @@ -20,7 +20,7 @@ import PendingChangesUploader from "./Logic/Actors/PendingChangesUploader"; import {Relation} from "./Logic/Osm/ExtractRelations"; import OsmApiFeatureSource from "./Logic/FeatureSource/OsmApiFeatureSource"; import ChangeToElementsActor from "./Logic/Actors/ChangeToElementsActor"; -import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline"; +import FeatureSource from "./Logic/FeatureSource/FeatureSource"; /** * Contains the global state: a bunch of UI-event sources @@ -32,7 +32,7 @@ export default class State { public static state: State; - public readonly layoutToUse = new UIEventSource(undefined); + public readonly layoutToUse = new UIEventSource(undefined, "layoutToUse"); /** The mapping from id -> UIEventSource @@ -45,7 +45,7 @@ export default class State { /** The leaflet instance of the big basemap */ - public leafletMap = new UIEventSource(undefined); + public leafletMap = new UIEventSource(undefined, "leafletmap"); /** * Background layer id */ @@ -70,7 +70,7 @@ export default class State { }[]> = new UIEventSource<{ readonly isDisplayed: UIEventSource, readonly layerDef: LayerConfig; - }[]>([]) + }[]>([], "filteredLayers") /** @@ -101,13 +101,13 @@ export default class State { public readonly featureSwitchFakeUser: UIEventSource; - public readonly featurePipeline: FeaturePipeline; + public featurePipeline: FeatureSource; /** * The map location: currently centered lat, lon and zoom */ - public readonly locationControl = new UIEventSource(undefined); + public readonly locationControl = new UIEventSource(undefined, "locationControl"); public backgroundLayer; public readonly backgroundLayerId: UIEventSource; @@ -149,11 +149,13 @@ export default class State { .syncWith(LocalStorageSource.Get("lon"))); - this.locationControl = new UIEventSource({ + this.locationControl.setData({ zoom: Utils.asFloat(zoom.data), lat: Utils.asFloat(lat.data), lon: Utils.asFloat(lon.data), - }).addCallback((latlonz) => { + }) + this.locationControl.addCallback((latlonz) => { + // Sync th location controls zoom.setData(latlonz.zoom); lat.setData(latlonz.lat); lon.setData(latlonz.lon); diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index df29d2b72c..2205851886 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -21,6 +21,7 @@ import {InputElement} from "../Input/InputElement"; import Loc from "../../Models/Loc"; import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"; import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction"; +import Hash from "../../Logic/Web/Hash"; /* * The SimpleAddUI is a single panel, which can have multiple states: @@ -71,10 +72,11 @@ export default class SimpleAddUI extends Toggle { } return SimpleAddUI.CreateConfirmButton(preset, (tags, location) => { - let changes = - State.state.changes.applyAction(new CreateNewNodeAction(tags, location.lat, location.lon)) - State.state.selectedElement.setData(changes.newFeatures[0]); + const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon) + State.state.changes.applyAction(newElementAction) selectedPreset.setData(undefined) + isShown.setData(false) + Hash.hash.setData(newElementAction.newElementId) }, () => { selectedPreset.setData(undefined) }) @@ -119,16 +121,16 @@ export default class SimpleAddUI extends Toggle { lon: location.data.lon, zoom: 19 }); - + let backgroundLayer = undefined; - if(preset.preciseInput.preferredBackground){ - backgroundLayer= AvailableBaseLayers.SelectBestLayerAccordingTo(locationSrc, new UIEventSource(preset.preciseInput.preferredBackground)) + if (preset.preciseInput.preferredBackground) { + backgroundLayer = AvailableBaseLayers.SelectBestLayerAccordingTo(locationSrc, new UIEventSource(preset.preciseInput.preferredBackground)) } - + preciseInput = new LocationInput({ mapBackground: backgroundLayer, - centerLocation:locationSrc - + centerLocation: locationSrc + }) preciseInput.SetClass("h-32 rounded-xl overflow-hidden border border-gray").SetStyle("height: 12rem;") } @@ -143,7 +145,7 @@ export default class SimpleAddUI extends Toggle { .onClick(() => { confirm(preset.tags, (preciseInput?.GetValue() ?? location).data); }); - + if (preciseInput !== undefined) { confirmButton = new Combine([preciseInput, confirmButton]) } @@ -239,7 +241,7 @@ export default class SimpleAddUI extends Toggle { for (const preset of presets) { const tags = TagUtils.KVtoProperties(preset.tags ?? []); - let icon:() => BaseUIElement = () => layer.layerDef.GenerateLeafletStyle(new UIEventSource(tags), false).icon.html + let icon: () => BaseUIElement = () => layer.layerDef.GenerateLeafletStyle(new UIEventSource(tags), false).icon.html .SetClass("w-12 h-12 block relative"); const presetInfo: PresetInfo = { tags: preset.tags, diff --git a/UI/Popup/SplitRoadWizard.ts b/UI/Popup/SplitRoadWizard.ts index 60b0527f98..962c55a4d5 100644 --- a/UI/Popup/SplitRoadWizard.ts +++ b/UI/Popup/SplitRoadWizard.ts @@ -92,18 +92,24 @@ export default class SplitRoadWizard extends Toggle { // Save button const saveButton = new Button(t.split.Clone(), () => { hasBeenSplit.setData(true) - OsmObject.DownloadObject(id).addCallbackAndRunD(way => { - OsmObject.DownloadReferencingRelations(id).addCallbackAndRunD( - partOf => { - const splitAction = new SplitAction( - way, way.asGeoJson(), partOf, splitPoints.data.map(ff => ff.feature) - ) - State.state.changes.applyAction(splitAction) - } - ) - + const way = OsmObject.DownloadObject(id) + const partOfSrc = OsmObject.DownloadReferencingRelations(id); + let hasRun = false + way.map(way => { + const partOf = partOfSrc.data + if(way === undefined || partOf === undefined){ + return; } - ) + if(hasRun){ + return + } + hasRun = true + const splitAction = new SplitAction( + way, way.asGeoJson(), partOf, splitPoints.data.map(ff => ff.feature) + ) + State.state.changes.applyAction(splitAction) + + }, [partOfSrc]) }); @@ -123,7 +129,7 @@ export default class SplitRoadWizard extends Toggle { const splitTitle = new Title(t.splitTitle); - const mapView = new Combine([splitTitle, miniMap, new Combine([cancelButton, saveToggle])]); + const mapView = new Combine([splitTitle, miniMap, new Combine([cancelButton, saveToggle]).SetClass("flex flex-row")]); mapView.SetClass("question") const confirm = new Toggle(mapView, splitToggle, splitClicked); super(t.hasBeenSplit.Clone(), confirm, hasBeenSplit) diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index 7eb7182187..36fb62efc1 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -61,7 +61,6 @@ export default class ShowDataLayer { } const allFeats = features.data.map(ff => ff.feature); - console.log("Rendering ",allFeats, "features at layer ", name) geoLayer = self.CreateGeojsonLayer(); for (const feat of allFeats) { if (feat === undefined) { @@ -87,6 +86,7 @@ export default class ShowDataLayer { console.error(e) } } + State.state.selectedElement.ping() } features.addCallback(() => update()); diff --git a/UI/SubstitutedTranslation.ts b/UI/SubstitutedTranslation.ts index 43352aa5b4..361540e65f 100644 --- a/UI/SubstitutedTranslation.ts +++ b/UI/SubstitutedTranslation.ts @@ -19,7 +19,6 @@ export class SubstitutedTranslation extends VariableUiElement { const extraMappings: SpecialVisualization[] = []; mapping?.forEach((value, key) => { - console.log("KV:", key, value) extraMappings.push( { funcName: key, @@ -73,11 +72,6 @@ export class SubstitutedTranslation extends VariableUiElement { } }[] { - if (extraMappings.length > 0) { - - console.log("Extra mappings are", extraMappings) - } - for (const knownSpecial of SpecialVisualizations.specialVisualizations.concat(extraMappings)) { // Note: the '.*?' in the regex reads as 'any character, but in a non-greedy way' diff --git a/UI/i18n/Translation.ts b/UI/i18n/Translation.ts index e6e2dfba2b..f153b1e653 100644 --- a/UI/i18n/Translation.ts +++ b/UI/i18n/Translation.ts @@ -109,9 +109,9 @@ export class Translation extends BaseUIElement { // @ts-ignore const date: Date = el; rtext = date.toLocaleString(); - } else if (el.ConstructElement() === undefined) { - console.error("InnerREnder is not defined", el); - throw "Hmmm, el.InnerRender is not defined?" + } else if (el.ConstructElement === undefined) { + console.error("ConstructElement is not defined", el); + throw "ConstructElement is not defined, you are working with a "+(typeof el)+":"+(el.constructor.name) } else { Translation.forcedLanguage = lang; // This is a very dirty hack - it'll bite me one day rtext = el.ConstructElement().innerHTML; diff --git a/assets/themes/cyclestreets/cyclestreets.json b/assets/themes/cyclestreets/cyclestreets.json index da3f5bcc27..ea8026cb32 100644 --- a/assets/themes/cyclestreets/cyclestreets.json +++ b/assets/themes/cyclestreets/cyclestreets.json @@ -33,7 +33,7 @@ "startZoom": 14, "startLon": 3.2228, "maintainer": "MapComplete", - "widenfactor": 0.05, + "widenfactor": 0.01, "roamingRenderings": [ { "question": {