forked from MapComplete/MapComplete
Add robustness when run via console, formatting
This commit is contained in:
parent
83af5adaea
commit
89d4a6bcce
11 changed files with 118 additions and 67 deletions
|
@ -23,11 +23,11 @@ export default class AvailableBaseLayers {
|
||||||
private static implementation: AvailableBaseLayersObj
|
private static implementation: AvailableBaseLayersObj
|
||||||
|
|
||||||
static AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]> {
|
static AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]> {
|
||||||
return AvailableBaseLayers.implementation.AvailableLayersAt(location);
|
return AvailableBaseLayers.implementation?.AvailableLayersAt(location) ?? new UIEventSource<BaseLayer[]>([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer> {
|
static SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer> {
|
||||||
return AvailableBaseLayers.implementation.SelectBestLayerAccordingTo(location, preferedCategory);
|
return AvailableBaseLayers.implementation?.SelectBestLayerAccordingTo(location, preferedCategory) ?? new UIEventSource<BaseLayer>(undefined);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {UIEventSource} from "../UIEventSource";
|
||||||
import BaseLayer from "../../Models/BaseLayer";
|
import BaseLayer from "../../Models/BaseLayer";
|
||||||
import AvailableBaseLayers from "./AvailableBaseLayers";
|
import AvailableBaseLayers from "./AvailableBaseLayers";
|
||||||
import Loc from "../../Models/Loc";
|
import Loc from "../../Models/Loc";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current background layer to a layer that is actually available
|
* Sets the current background layer to a layer that is actually available
|
||||||
|
@ -12,6 +13,11 @@ export default class BackgroundLayerResetter {
|
||||||
location: UIEventSource<Loc>,
|
location: UIEventSource<Loc>,
|
||||||
availableLayers: UIEventSource<BaseLayer[]>,
|
availableLayers: UIEventSource<BaseLayer[]>,
|
||||||
defaultLayerId: string = undefined) {
|
defaultLayerId: string = undefined) {
|
||||||
|
|
||||||
|
if(Utils.runningFromConsole){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
defaultLayerId = defaultLayerId ?? AvailableBaseLayers.osmCarto.id;
|
defaultLayerId = defaultLayerId ?? AvailableBaseLayers.osmCarto.id;
|
||||||
|
|
||||||
// Change the baselayer back to OSM if we go out of the current range of the layer
|
// Change the baselayer back to OSM if we go out of the current range of the layer
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {Changes} from "../Osm/Changes";
|
import {Changes} from "../Osm/Changes";
|
||||||
import Constants from "../../Models/Constants";
|
import Constants from "../../Models/Constants";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export default class PendingChangesUploader {
|
export default class PendingChangesUploader {
|
||||||
|
|
||||||
|
@ -30,6 +31,10 @@ export default class PendingChangesUploader {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(Utils.runningFromConsole){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('mouseout', e => {
|
document.addEventListener('mouseout', e => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!e.toElement && !e.relatedTarget) {
|
if (!e.toElement && !e.relatedTarget) {
|
||||||
|
|
|
@ -9,6 +9,13 @@ import {OsmConnection} from "../Osm/OsmConnection";
|
||||||
|
|
||||||
export default class SelectedElementTagsUpdater {
|
export default class SelectedElementTagsUpdater {
|
||||||
|
|
||||||
|
private static readonly metatags = new Set(["timestamp",
|
||||||
|
"version",
|
||||||
|
"changeset",
|
||||||
|
"user",
|
||||||
|
"uid",
|
||||||
|
"id"] )
|
||||||
|
|
||||||
constructor(state: {
|
constructor(state: {
|
||||||
selectedElement: UIEventSource<any>,
|
selectedElement: UIEventSource<any>,
|
||||||
allElements: ElementStorage,
|
allElements: ElementStorage,
|
||||||
|
@ -18,15 +25,15 @@ export default class SelectedElementTagsUpdater {
|
||||||
|
|
||||||
|
|
||||||
state.osmConnection.isLoggedIn.addCallbackAndRun(isLoggedIn => {
|
state.osmConnection.isLoggedIn.addCallbackAndRun(isLoggedIn => {
|
||||||
if(isLoggedIn){
|
if (isLoggedIn) {
|
||||||
SelectedElementTagsUpdater.installCallback(state)
|
SelectedElementTagsUpdater.installCallback(state)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static installCallback(state: {
|
public static installCallback(state: {
|
||||||
selectedElement: UIEventSource<any>,
|
selectedElement: UIEventSource<any>,
|
||||||
allElements: ElementStorage,
|
allElements: ElementStorage,
|
||||||
changes: Changes,
|
changes: Changes,
|
||||||
|
@ -36,80 +43,99 @@ export default class SelectedElementTagsUpdater {
|
||||||
|
|
||||||
state.selectedElement.addCallbackAndRunD(s => {
|
state.selectedElement.addCallbackAndRunD(s => {
|
||||||
let id = s.properties?.id
|
let id = s.properties?.id
|
||||||
|
|
||||||
const backendUrl = state.osmConnection._oauth_config.url
|
const backendUrl = state.osmConnection._oauth_config.url
|
||||||
if(id.startsWith(backendUrl)){
|
if (id.startsWith(backendUrl)) {
|
||||||
id = id.substring(backendUrl.length)
|
id = id.substring(backendUrl.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(id.startsWith("way") || id.startsWith("node") || id.startsWith("relation"))){
|
if (!(id.startsWith("way") || id.startsWith("node") || id.startsWith("relation"))) {
|
||||||
// This object is _not_ from OSM, so we skip it!
|
// This object is _not_ from OSM, so we skip it!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id.indexOf("-") >= 0){
|
if (id.indexOf("-") >= 0) {
|
||||||
// This is a new object
|
// This is a new object
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
OsmObject.DownloadPropertiesOf(id).then(latestTags => {
|
||||||
OsmObject.DownloadPropertiesOf(id).then(tags => {
|
SelectedElementTagsUpdater.applyUpdate(state, latestTags, id)
|
||||||
SelectedElementTagsUpdater.applyUpdate(state, tags, id)
|
|
||||||
}).catch(e => {
|
|
||||||
console.error("Could not update tags of ", id, "due to", e)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static applyUpdate(state: {
|
public static applyUpdate(state: {
|
||||||
selectedElement: UIEventSource<any>,
|
selectedElement: UIEventSource<any>,
|
||||||
allElements: ElementStorage,
|
allElements: ElementStorage,
|
||||||
changes: Changes,
|
changes: Changes,
|
||||||
osmConnection: OsmConnection
|
osmConnection: OsmConnection
|
||||||
}, latestTags: any, id: string
|
}, latestTags: any, id: string
|
||||||
) {
|
) {
|
||||||
const pendingChanges = state.changes.pendingChanges.data
|
try {
|
||||||
.filter(change => change.type +"/"+ change.id === id)
|
|
||||||
.filter(change => change.tags !== undefined);
|
const pendingChanges = state.changes.pendingChanges.data
|
||||||
|
.filter(change => change.type + "/" + change.id === id)
|
||||||
for (const pendingChange of pendingChanges) {
|
.filter(change => change.tags !== undefined);
|
||||||
const tagChanges = pendingChange.tags;
|
|
||||||
for (const tagChange of tagChanges) {
|
for (const pendingChange of pendingChanges) {
|
||||||
const key = tagChange.k
|
const tagChanges = pendingChange.tags;
|
||||||
const v = tagChange.v
|
for (const tagChange of tagChanges) {
|
||||||
if (v === undefined || v === "") {
|
const key = tagChange.k
|
||||||
delete latestTags[key]
|
const v = tagChange.v
|
||||||
} else {
|
if (v === undefined || v === "") {
|
||||||
latestTags[key] = v
|
delete latestTags[key]
|
||||||
|
} else {
|
||||||
|
latestTags[key] = v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// With the changes applied, we merge them onto the upstream object
|
// With the changes applied, we merge them onto the upstream object
|
||||||
let somethingChanged = false;
|
let somethingChanged = false;
|
||||||
const currentTagsSource = state.allElements.getEventSourceById(id);
|
const currentTagsSource = state.allElements.getEventSourceById(id);
|
||||||
const currentTags = currentTagsSource.data
|
const currentTags = currentTagsSource.data
|
||||||
for (const key in latestTags) {
|
for (const key in latestTags) {
|
||||||
let osmValue = latestTags[key]
|
let osmValue = latestTags[key]
|
||||||
|
|
||||||
if(typeof osmValue === "number"){
|
|
||||||
osmValue = ""+osmValue
|
|
||||||
}
|
|
||||||
|
|
||||||
const localValue = currentTags[key]
|
|
||||||
if (localValue !== osmValue) {
|
|
||||||
console.log("Local value for ", key ,":", localValue, "upstream", osmValue)
|
|
||||||
somethingChanged = true;
|
|
||||||
currentTags[key] = osmValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (somethingChanged) {
|
|
||||||
console.log("Detected upstream changes to the object when opening it, updating...")
|
|
||||||
currentTagsSource.ping()
|
|
||||||
}else{
|
|
||||||
console.debug("Fetched latest tags for ", id, "but detected no changes")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (typeof osmValue === "number") {
|
||||||
|
osmValue = "" + osmValue
|
||||||
|
}
|
||||||
|
|
||||||
|
const localValue = currentTags[key]
|
||||||
|
if (localValue !== osmValue) {
|
||||||
|
console.log("Local value for ", key, ":", localValue, "upstream", osmValue)
|
||||||
|
somethingChanged = true;
|
||||||
|
currentTags[key] = osmValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const currentKey in currentTags) {
|
||||||
|
if (currentKey.startsWith("_")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if(this.metatags.has(currentKey)){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (currentKey in latestTags) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
console.log("Removing key as deleted upstream", currentKey)
|
||||||
|
delete currentTags[currentKey]
|
||||||
|
somethingChanged = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (somethingChanged) {
|
||||||
|
console.log("Detected upstream changes to the object when opening it, updating...")
|
||||||
|
currentTagsSource.ping()
|
||||||
|
} else {
|
||||||
|
console.debug("Fetched latest tags for ", id, "but detected no changes")
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Updating the tags of selected element ", id, "failed due to", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import TagRenderingAnswer from "../../UI/Popup/TagRenderingAnswer";
|
||||||
import Combine from "../../UI/Base/Combine";
|
import Combine from "../../UI/Base/Combine";
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||||
import {ElementStorage} from "../ElementStorage";
|
import {ElementStorage} from "../ElementStorage";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export default class TitleHandler {
|
export default class TitleHandler {
|
||||||
constructor(state : {
|
constructor(state : {
|
||||||
|
@ -38,6 +39,9 @@ export default class TitleHandler {
|
||||||
|
|
||||||
|
|
||||||
currentTitle.addCallbackAndRunD(title => {
|
currentTitle.addCallbackAndRunD(title => {
|
||||||
|
if(Utils.runningFromConsole){
|
||||||
|
return
|
||||||
|
}
|
||||||
document.title = title
|
document.title = title
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,13 @@ export default class AllImageProviders {
|
||||||
)
|
)
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
public static defaultKeys = [].concat(AllImageProviders.ImageAttributionSource.map(provider => provider.defaultKeyPrefixes))
|
||||||
|
|
||||||
|
|
||||||
private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<string, UIEventSource<ProvidedImage[]>>()
|
private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<string, UIEventSource<ProvidedImage[]>>()
|
||||||
|
|
||||||
public static LoadImagesFor(tags: UIEventSource<any>, tagKey?: string): UIEventSource<ProvidedImage[]> {
|
public static LoadImagesFor(tags: UIEventSource<any>, tagKey?: string[]): UIEventSource<ProvidedImage[]> {
|
||||||
if (tags.data.id === undefined) {
|
if (tags.data.id === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +46,7 @@ export default class AllImageProviders {
|
||||||
|
|
||||||
let prefixes = imageProvider.defaultKeyPrefixes
|
let prefixes = imageProvider.defaultKeyPrefixes
|
||||||
if(tagKey !== undefined){
|
if(tagKey !== undefined){
|
||||||
prefixes = [...prefixes, tagKey]
|
prefixes = tagKey
|
||||||
}
|
}
|
||||||
|
|
||||||
const singleSource = imageProvider.GetRelevantUrls(tags, {
|
const singleSource = imageProvider.GetRelevantUrls(tags, {
|
||||||
|
|
|
@ -27,7 +27,8 @@ export default class ImgurUploader {
|
||||||
files,
|
files,
|
||||||
function (url) {
|
function (url) {
|
||||||
console.log("File saved at", url);
|
console.log("File saved at", url);
|
||||||
self.success.setData([...self.success.data, url]);
|
self.success.data.push(url)
|
||||||
|
self.success.ping();
|
||||||
self._handleSuccessUrl(url);
|
self._handleSuccessUrl(url);
|
||||||
},
|
},
|
||||||
function () {
|
function () {
|
||||||
|
|
|
@ -97,6 +97,7 @@ export class Changes {
|
||||||
console.log("Is already uploading... Abort")
|
console.log("Is already uploading... Abort")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log("Uploading changes due to: ", flushreason)
|
||||||
this.isUploading.setData(true)
|
this.isUploading.setData(true)
|
||||||
|
|
||||||
this.flushChangesAsync()
|
this.flushChangesAsync()
|
||||||
|
@ -287,7 +288,7 @@ export class Changes {
|
||||||
v = undefined;
|
v = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldV = obj.type[k]
|
const oldV = obj.tags[k]
|
||||||
if (oldV === v) {
|
if (oldV === v) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,9 @@ export abstract class OsmObject {
|
||||||
|
|
||||||
const url = `${OsmObject.backendURL}api/0.6/${id}`;
|
const url = `${OsmObject.backendURL}api/0.6/${id}`;
|
||||||
const rawData = await Utils.downloadJsonCached(url, 1000)
|
const rawData = await Utils.downloadJsonCached(url, 1000)
|
||||||
return rawData.elements[0].tags
|
const tags = rawData.elements[0].tags
|
||||||
|
console.log("Tags are", tags)
|
||||||
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
static async DownloadObjectAsync(id: string): Promise<OsmObject> {
|
static async DownloadObjectAsync(id: string): Promise<OsmObject> {
|
||||||
|
@ -263,7 +265,7 @@ export abstract class OsmObject {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const v = this.tags[key];
|
const v = this.tags[key];
|
||||||
if (v !== "") {
|
if (v !== "" && v !== undefined) {
|
||||||
tags += ' <tag k="' + Utils.EncodeXmlValue(key) + '" v="' + Utils.EncodeXmlValue(this.tags[key]) + '"/>\n'
|
tags += ' <tag k="' + Utils.EncodeXmlValue(key) + '" v="' + Utils.EncodeXmlValue(this.tags[key]) + '"/>\n'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
import {QueryParameters} from "../Web/QueryParameters";
|
import {QueryParameters} from "../Web/QueryParameters";
|
||||||
import Constants from "../../Models/Constants";
|
import Constants from "../../Models/Constants";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export default class FeatureSwitchState {
|
export default class FeatureSwitchState {
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ export default class FeatureSwitchState {
|
||||||
|
|
||||||
|
|
||||||
let testingDefaultValue = false;
|
let testingDefaultValue = false;
|
||||||
if (this.featureSwitchApiURL.data !== "osm-test" &&
|
if (this.featureSwitchApiURL.data !== "osm-test" && !Utils.runningFromConsole &&
|
||||||
(location.hostname === "localhost" || location.hostname === "127.0.0.1")) {
|
(location.hostname === "localhost" || location.hostname === "127.0.0.1")) {
|
||||||
testingDefaultValue = true
|
testingDefaultValue = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,6 +286,9 @@ export class UIEventSource<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public stabilized(millisToStabilize): UIEventSource<T> {
|
public stabilized(millisToStabilize): UIEventSource<T> {
|
||||||
|
if(Utils.runningFromConsole){
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
const newSource = new UIEventSource<T>(this.data);
|
const newSource = new UIEventSource<T>(this.data);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue