Add move option, enable move and delete option on most layers

This commit is contained in:
pietervdvn 2021-10-14 03:46:09 +02:00
parent 0a3eb966c1
commit 7e2b73ac5d
33 changed files with 454 additions and 104 deletions

View file

@ -18,7 +18,6 @@ export default class ChangeLocationAction extends OsmChangeAction {
this._id = Number(id.substring("node/".length)) this._id = Number(id.substring("node/".length))
this._newLonLat = newLonLat; this._newLonLat = newLonLat;
this._meta = meta; this._meta = meta;
throw "TODO"
} }
protected async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> { protected async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {

View file

@ -59,14 +59,13 @@ export abstract class OsmObject {
static async DownloadPropertiesOf(id: string): Promise<any> { static async DownloadPropertiesOf(id: string): Promise<any> {
const splitted = id.split("/"); const splitted = id.split("/");
const type = splitted[0];
const idN = Number(splitted[1]); const idN = Number(splitted[1]);
if (idN < 0) { if (idN < 0) {
return undefined; return undefined;
} }
const url = `${OsmObject.backendURL}api/0.6/${id}`; const url = `${OsmObject.backendURL}api/0.6/${id}`;
const rawData = await Utils.downloadJson(url) const rawData = await Utils.downloadJsonCached(url, 1000)
return rawData.elements[0].tags return rawData.elements[0].tags
} }
@ -80,7 +79,7 @@ export abstract class OsmObject {
const full = (id.startsWith("way")) ? "/full" : ""; const full = (id.startsWith("way")) ? "/full" : "";
const url = `${OsmObject.backendURL}api/0.6/${id}${full}`; const url = `${OsmObject.backendURL}api/0.6/${id}${full}`;
const rawData = await Utils.downloadJson(url) const rawData = await Utils.downloadJsonCached(url, 1000)
// 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) // 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); const parsed = OsmObject.ParseObjects(rawData.elements);
// Lets fetch the object we need // Lets fetch the object we need
@ -105,7 +104,7 @@ export abstract class OsmObject {
* Beware: their geometry will be incomplete! * Beware: their geometry will be incomplete!
*/ */
public static DownloadReferencingWays(id: string): Promise<OsmWay[]> { public static DownloadReferencingWays(id: string): Promise<OsmWay[]> {
return Utils.downloadJson(`${OsmObject.backendURL}api/0.6/${id}/ways`).then( return Utils.downloadJsonCached(`${OsmObject.backendURL}api/0.6/${id}/ways`, 60 * 1000).then(
data => { data => {
return data.elements.map(wayInfo => { return data.elements.map(wayInfo => {
const way = new OsmWay(wayInfo.id) const way = new OsmWay(wayInfo.id)
@ -121,7 +120,7 @@ export abstract class OsmObject {
* Beware: their geometry will be incomplete! * Beware: their geometry will be incomplete!
*/ */
public static async DownloadReferencingRelations(id: string): Promise<OsmRelation[]> { public static async DownloadReferencingRelations(id: string): Promise<OsmRelation[]> {
const data = await Utils.downloadJson(`${OsmObject.backendURL}api/0.6/${id}/relations`) const data = await Utils.downloadJsonCached(`${OsmObject.backendURL}api/0.6/${id}/relations`, 60 * 1000)
return data.elements.map(wayInfo => { return data.elements.map(wayInfo => {
const rel = new OsmRelation(wayInfo.id) const rel = new OsmRelation(wayInfo.id)
rel.LoadData(wayInfo) rel.LoadData(wayInfo)
@ -139,7 +138,7 @@ export abstract class OsmObject {
const idN = Number(splitted[1]); const idN = Number(splitted[1]);
const src = new UIEventSource<OsmObject[]>([]); const src = new UIEventSource<OsmObject[]>([]);
OsmObject.historyCache.set(id, src); OsmObject.historyCache.set(id, src);
Utils.downloadJson(`${OsmObject.backendURL}api/0.6/${type}/${idN}/history`).then(data => { Utils.downloadJsonCached(`${OsmObject.backendURL}api/0.6/${type}/${idN}/history`, 10 * 60 * 1000).then(data => {
const elements: any[] = data.elements; const elements: any[] = data.elements;
const osmObjects: OsmObject[] = [] const osmObjects: OsmObject[] = []
for (const element of elements) { for (const element of elements) {

View file

@ -3,6 +3,7 @@ import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
import FilterConfigJson from "./FilterConfigJson"; import FilterConfigJson from "./FilterConfigJson";
import {DeleteConfigJson} from "./DeleteConfigJson"; import {DeleteConfigJson} from "./DeleteConfigJson";
import UnitConfigJson from "./UnitConfigJson"; import UnitConfigJson from "./UnitConfigJson";
import MoveConfigJson from "./MoveConfigJson";
/** /**
* Configuration for a single layer * Configuration for a single layer
@ -314,6 +315,18 @@ export interface LayerConfigJson {
*/ */
deletion?: boolean | DeleteConfigJson deletion?: boolean | DeleteConfigJson
/**
* Indicates if a point can be moved and configures the modalities.
*
* A feature can be moved by MapComplete if:
*
* - It is a point
* - The point is _not_ part of a way or a a relation.
*
* Off by default. Can be enabled by setting this flag or by configuring.
*/
allowMove?: boolean | MoveConfigJson
/** /**
* IF set, a 'split this road' button is shown * IF set, a 'split this road' button is shown
*/ */

View file

@ -0,0 +1,12 @@
export default interface MoveConfigJson {
/**
* One default reason to move a point is to improve accuracy.
* Set to false to disable this reason
*/
enableImproveAccuracy?: true | boolean
/**
* One default reason to move a point is because it has relocated
* Set to false to disable this reason
*/
enableRelocation?: true | boolean
}

View file

@ -19,6 +19,7 @@ import {Unit} from "../Unit";
import DeleteConfig from "./DeleteConfig"; import DeleteConfig from "./DeleteConfig";
import Svg from "../../Svg"; import Svg from "../../Svg";
import Img from "../../UI/Base/Img"; import Img from "../../UI/Base/Img";
import MoveConfig from "./MoveConfig";
export default class LayerConfig { export default class LayerConfig {
static WAYHANDLING_DEFAULT = 0; static WAYHANDLING_DEFAULT = 0;
@ -49,6 +50,7 @@ export default class LayerConfig {
wayHandling: number; wayHandling: number;
public readonly units: Unit[]; public readonly units: Unit[];
public readonly deletion: DeleteConfig | null; public readonly deletion: DeleteConfig | null;
public readonly allowMove: MoveConfig | null
public readonly allowSplit: boolean public readonly allowSplit: boolean
presets: PresetConfig[]; presets: PresetConfig[];
@ -138,10 +140,10 @@ export default class LayerConfig {
const key = kv.substring(0, index); const key = kv.substring(0, index);
const code = kv.substring(index + 1); const code = kv.substring(index + 1);
try{ try {
new Function("feat", "return " + code + ";"); new Function("feat", "return " + code + ";");
}catch(e){ } catch (e) {
throw `Invalid function definition: code ${code} is invalid:${e} (at ${context})` throw `Invalid function definition: code ${code} is invalid:${e} (at ${context})`
} }
@ -155,8 +157,8 @@ export default class LayerConfig {
this.minzoom = json.minzoom ?? 0; this.minzoom = json.minzoom ?? 0;
this.minzoomVisible = json.minzoomVisible ?? this.minzoom; this.minzoomVisible = json.minzoomVisible ?? this.minzoom;
this.wayHandling = json.wayHandling ?? 0; this.wayHandling = json.wayHandling ?? 0;
if(json.presets !== undefined && json.presets?.map === undefined){ if (json.presets !== undefined && json.presets?.map === undefined) {
throw "Presets should be a list of items (at "+context+")" throw "Presets should be a list of items (at " + context + ")"
} }
this.presets = (json.presets ?? []).map((pr, i) => { this.presets = (json.presets ?? []).map((pr, i) => {
@ -294,7 +296,7 @@ export default class LayerConfig {
const missingIds = json.tagRenderings?.filter(tr => typeof tr !== "string" && tr["builtin"] === undefined && tr["id"] === undefined) ?? []; const missingIds = json.tagRenderings?.filter(tr => typeof tr !== "string" && tr["builtin"] === undefined && tr["id"] === undefined) ?? [];
if(missingIds.length > 0 && official){ if (missingIds.length > 0 && official) {
console.error("Some tagRenderings of", this.id, "are missing an id:", missingIds) console.error("Some tagRenderings of", this.id, "are missing an id:", missingIds)
throw "Missing ids in tagrenderings" throw "Missing ids in tagrenderings"
} }
@ -303,8 +305,8 @@ export default class LayerConfig {
return new FilterConfig(option, `${context}.filter-[${i}]`) return new FilterConfig(option, `${context}.filter-[${i}]`)
}); });
if(json["filters"] !== undefined){ if (json["filters"] !== undefined) {
throw "Error in "+context+": use 'filter' instead of 'filters'" throw "Error in " + context + ": use 'filter' instead of 'filters'"
} }
const titleIcons = []; const titleIcons = [];
@ -369,6 +371,16 @@ export default class LayerConfig {
this.deletion = new DeleteConfig(json.deletion, `${context}.deletion`); this.deletion = new DeleteConfig(json.deletion, `${context}.deletion`);
} }
this.allowMove = null
if (json.allowMove === false) {
this.allowMove = null;
} else if (json.allowMove === true) {
this.allowMove = new MoveConfig({}, context + ".allowMove")
} else if (json.allowMove !== undefined && json.allowMove !== false) {
this.allowMove = new MoveConfig(json.allowMove, context + ".allowMove")
}
if (json["showIf"] !== undefined) { if (json["showIf"] !== undefined) {
throw ( throw (
"Invalid key on layerconfig " + "Invalid key on layerconfig " +

View file

@ -0,0 +1,17 @@
import MoveConfigJson from "./Json/MoveConfigJson";
export default class MoveConfig {
public readonly enableImproveAccuracy: boolean
public readonly enableRelocation: boolean
constructor(json: MoveConfigJson, context: string) {
this.enableImproveAccuracy = json.enableImproveAccuracy ?? true
this.enableRelocation = json.enableRelocation ?? true
if (!(this.enableRelocation || this.enableImproveAccuracy)) {
throw "At least one default move reason should be allowed (at " + context + ")"
}
}
}

View file

@ -15,6 +15,7 @@ import {BBox} from "../../Logic/BBox";
import {FixedUiElement} from "../Base/FixedUiElement"; import {FixedUiElement} from "../Base/FixedUiElement";
import ShowDataLayer from "../ShowDataLayer/ShowDataLayer"; import ShowDataLayer from "../ShowDataLayer/ShowDataLayer";
import BaseUIElement from "../BaseUIElement"; import BaseUIElement from "../BaseUIElement";
import Toggle from "./Toggle";
export default class LocationInput extends InputElement<Loc> implements MinimapObj { export default class LocationInput extends InputElement<Loc> implements MinimapObj {
@ -161,6 +162,11 @@ export default class LocationInput extends InputElement<Loc> implements MinimapO
protected InnerConstructElement(): HTMLElement { protected InnerConstructElement(): HTMLElement {
try { try {
const self = this; const self = this;
const hasMoved = new UIEventSource(false)
this.GetValue().addCallbackAndRunD(_ => {
hasMoved.setData(true)
return true;
})
this.clickLocation.addCallbackAndRunD(location => this._centerLocation.setData(location)) this.clickLocation.addCallbackAndRunD(location => this._centerLocation.setData(location))
if (this._snapTo !== undefined) { if (this._snapTo !== undefined) {
@ -213,8 +219,8 @@ export default class LocationInput extends InputElement<Loc> implements MinimapO
]).SetClass("block w-0 h-0 z-10 relative") ]).SetClass("block w-0 h-0 z-10 relative")
.SetStyle("background: rgba(255, 128, 128, 0.21); left: 50%; top: 50%; opacity: 0.5"), .SetStyle("background: rgba(255, 128, 128, 0.21); left: 50%; top: 50%; opacity: 0.5"),
new Combine([ new Toggle(undefined,
animatedHand]) animatedHand, hasMoved)
.SetClass("block w-0 h-0 z-10 relative") .SetClass("block w-0 h-0 z-10 relative")
.SetStyle("left: calc(50% + 3rem); top: calc(50% + 2rem); opacity: 0.7"), .SetStyle("left: calc(50% + 3rem); top: calc(50% + 2rem); opacity: 0.7"),

View file

@ -17,6 +17,7 @@ import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
import {Translation} from "../i18n/Translation"; import {Translation} from "../i18n/Translation";
import {Utils} from "../../Utils"; import {Utils} from "../../Utils";
import {SubstitutedTranslation} from "../SubstitutedTranslation"; import {SubstitutedTranslation} from "../SubstitutedTranslation";
import MoveWizard from "./MoveWizard";
export default class FeatureInfoBox extends ScrollableFullScreen { export default class FeatureInfoBox extends ScrollableFullScreen {
@ -72,6 +73,19 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
editElements.push(questionBox); editElements.push(questionBox);
} }
if(layerConfig.allowMove) {
editElements.push(
new VariableUiElement(tags.map(tags => tags.id).map(id => {
const feature = State.state.allElements.ContainingFeatures.get(id)
return new MoveWizard(
feature,
State.state,
layerConfig.allowMove
);
})
)
);
}
if (layerConfig.deletion) { if (layerConfig.deletion) {
editElements.push( editElements.push(

View file

@ -15,13 +15,17 @@ import {OsmObject} from "../../Logic/Osm/OsmObject";
import {Changes} from "../../Logic/Osm/Changes"; import {Changes} from "../../Logic/Osm/Changes";
import ChangeLocationAction from "../../Logic/Osm/Actions/ChangeLocationAction"; import ChangeLocationAction from "../../Logic/Osm/Actions/ChangeLocationAction";
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"; import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import MoveConfig from "../../Models/ThemeConfig/MoveConfig";
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers";
import {ElementStorage} from "../../Logic/ElementStorage";
interface MoveReason { interface MoveReason {
text: Translation | string, text: Translation | string,
invitingText: Translation | string,
icon: string | BaseUIElement, icon: string | BaseUIElement,
changesetCommentValue: string, changesetCommentValue: string,
lockBounds: true | boolean, lockBounds: true | boolean,
background: undefined | "map" | "photo", background: undefined | "map" | "photo" | string | string[],
startZoom: number, startZoom: number,
minZoom: number minZoom: number
} }
@ -36,13 +40,9 @@ export default class MoveWizard extends Toggle {
osmConnection: OsmConnection, osmConnection: OsmConnection,
featureSwitchUserbadge: UIEventSource<boolean>, featureSwitchUserbadge: UIEventSource<boolean>,
changes: Changes, changes: Changes,
layoutToUse: LayoutConfig layoutToUse: LayoutConfig,
}, options?: { allElements: ElementStorage
reasons?: MoveReason[] }, options : MoveConfig) {
disableDefaultReasons?: false | boolean
}) {
options = options ?? {}
const t = Translations.t.move const t = Translations.t.move
const loginButton = new Toggle( const loginButton = new Toggle(
@ -51,14 +51,53 @@ export default class MoveWizard extends Toggle {
state.featureSwitchUserbadge state.featureSwitchUserbadge
) )
const reasons: MoveReason[] = []
if (options.enableRelocation) {
reasons.push({
text: t.reasons.reasonRelocation.Clone(),
invitingText: t.inviteToMove.reasonRelocation.Clone(),
icon: Svg.relocation_svg(),
changesetCommentValue: "relocated",
lockBounds: false,
background: undefined,
startZoom: 12,
minZoom: 6
})
}
if(options.enableImproveAccuracy){
reasons.push({
text: t.reasons.reasonInaccurate.Clone(),
invitingText: t.inviteToMove.reasonInaccurate,
icon: Svg.crosshair_svg(),
changesetCommentValue: "improve_accuracy",
lockBounds: true,
background: "photo",
startZoom: 17,
minZoom: 16
})
}
const currentStep = new UIEventSource<"start" | "reason" | "pick_location" | "moved">("start") const currentStep = new UIEventSource<"start" | "reason" | "pick_location" | "moved">("start")
const moveReason = new UIEventSource<MoveReason>(undefined) const moveReason = new UIEventSource<MoveReason>(undefined)
const moveButton = new SubtleButton( let moveButton : BaseUIElement;
if(reasons.length === 1){
const reason = reasons[0]
moveReason.setData(reason)
moveButton = new SubtleButton(
reason.icon,
Translations.WT(reason.invitingText).Clone()
).onClick(() => {
currentStep.setData("pick_location")
})
}else{
moveButton = new SubtleButton(
Svg.move_ui(), Svg.move_ui(),
t.inviteToMove.Clone() t.inviteToMove.generic.Clone()
).onClick(() => { ).onClick(() => {
currentStep.setData("reason") currentStep.setData("reason")
}) })
}
const moveAgainButton = new SubtleButton( const moveAgainButton = new SubtleButton(
Svg.move_ui(), Svg.move_ui(),
@ -68,39 +107,7 @@ export default class MoveWizard extends Toggle {
}) })
const reasons: MoveReason[] = []
if (!options.disableDefaultReasons) {
reasons.push({
text: t.reasonRelocation.Clone(),
icon: Svg.relocation_svg(),
changesetCommentValue: "relocated",
lockBounds: false,
background: undefined,
startZoom: 12,
minZoom: 6
})
reasons.push({
text: t.reasonInaccurate.Clone(),
icon: Svg.crosshair_svg(),
changesetCommentValue: "improve_accuracy",
lockBounds: true,
background: "photo",
startZoom: 17,
minZoom: 16
})
}
for (const reason of options.reasons ?? []) {
reasons.push({
text: reason.text,
icon: reason.icon,
changesetCommentValue: reason.changesetCommentValue,
lockBounds: reason.lockBounds ?? true,
background: reason.background,
startZoom: reason.startZoom ?? 15,
minZoom: reason.minZoom
})
}
const selectReason = new Combine(reasons.map(r => new SubtleButton(r.icon, r.text).onClick(() => { const selectReason = new Combine(reasons.map(r => new SubtleButton(r.icon, r.text).onClick(() => {
moveReason.setData(r) moveReason.setData(r)
@ -124,7 +131,8 @@ export default class MoveWizard extends Toggle {
const locationInput = new LocationInput({ const locationInput = new LocationInput({
minZoom: reason.minZoom, minZoom: reason.minZoom,
centerLocation: loc centerLocation: loc,
mapBackground: AvailableBaseLayers.SelectBestLayerAccordingTo(loc, new UIEventSource(reason.background))
}) })
if (reason.lockBounds) { if (reason.lockBounds) {
@ -135,10 +143,14 @@ export default class MoveWizard extends Toggle {
const confirmMove = new SubtleButton(Svg.move_confirm_svg(), t.confirmMove) const confirmMove = new SubtleButton(Svg.move_confirm_svg(), t.confirmMove)
confirmMove.onClick(() => { confirmMove.onClick(() => {
state.changes.applyAction(new ChangeLocationAction(featureToMove.properties.id, [locationInput.GetValue().data.lon, locationInput.GetValue().data.lat], { const loc = locationInput.GetValue().data
state.changes.applyAction(new ChangeLocationAction(featureToMove.properties.id, [loc.lon, loc.lat], {
reason: Translations.WT(reason.text).textFor("en"), reason: Translations.WT(reason.text).textFor("en"),
theme: state.layoutToUse.icon theme: state.layoutToUse.id
})) }))
featureToMove.properties._lat = loc.lat
featureToMove.properties._lon = loc.lon
state.allElements.getEventSourceById(id).ping()
currentStep.setData("moved") currentStep.setData("moved")
}) })
const zoomInFurhter = t.zoomInFurther.Clone().SetClass("alert block m-6") const zoomInFurhter = t.zoomInFurther.Clone().SetClass("alert block m-6")

View file

@ -320,6 +320,19 @@ export class Utils {
) )
} }
private static _download_cache = new Map<string, {promise: Promise<any>, timestamp: number}>()
public static async downloadJsonCached(url: string, maxCacheTimeMs: number, headers?: any): Promise<any> {
const cached = Utils._download_cache.get(url)
if(cached !== undefined){
if((new Date().getTime() - cached.timestamp) <= maxCacheTimeMs){
return cached.promise
}
}
const promise = Utils.downloadJson(url, headers)
Utils._download_cache.set(url, {promise, timestamp: new Date().getTime()})
return await promise
}
public static async downloadJson(url: string, headers?: any): Promise<any> { public static async downloadJson(url: string, headers?: any): Promise<any> {
const injected = Utils.injectedDownloads[url] const injected = Utils.injectedDownloads[url]
if (injected !== undefined) { if (injected !== undefined) {

View file

@ -600,5 +600,18 @@
"preferredBackground": "photo" "preferredBackground": "photo"
} }
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity=bench",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -255,5 +255,18 @@
], ],
"multiAnswer": true "multiAnswer": true
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -145,5 +145,18 @@
"roaming": false, "roaming": false,
"id": "bike_cleaning-charge" "id": "bike_cleaning-charge"
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -508,5 +508,18 @@
}, },
"id": "Cargo bike capacity?" "id": "Cargo bike capacity?"
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -731,5 +731,18 @@
"service:bicycle:pump=no" "service:bicycle:pump=no"
] ]
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -100,5 +100,18 @@
"amenity=binoculars" "amenity=binoculars"
] ]
} }
},
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
} }
} }

View file

@ -296,5 +296,17 @@
} }
] ]
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
}
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -181,5 +181,11 @@
} }
] ]
} }
] ],
"deletion": {
"softDeletionTags": {
"and": ["amenity=","disused:amenity:={amenity}"]
}
},
"allowMove": true
} }

View file

@ -3655,5 +3655,18 @@
], ],
"eraseInvalidValues": true "eraseInvalidValues": true
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -539,5 +539,18 @@
}, },
"id": "defibrillator-fixme" "id": "defibrillator-fixme"
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:emergency:=defibrillator}",
"emergency="
] ]
},
"neededChangesets": 5
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -166,5 +166,18 @@
}, },
"condition": "_closest_other_drinking_water_id~*" "condition": "_closest_other_drinking_water_id~*"
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -624,5 +624,11 @@
} }
] ]
} }
] ],
"deletion": {
"softDeletionTags": {
"and": ["amenity=","disused:amenity:={amenity}"]
}
},
"allowMove": true
} }

View file

@ -187,5 +187,18 @@
}, },
"id": "ghost_bike-start_date" "id": "ghost_bike-start_date"
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"razed:memorial:=ghost_bike",
"memorial="
] ]
},
"neededChangesets": 50
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -53,5 +53,20 @@
"ru": "Информационный щит" "ru": "Информационный щит"
} }
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:tourism:=information",
"tourism=" ,
"razed:information=board",
"information="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -227,5 +227,18 @@
} }
} }
], ],
"wayHandling": 2 "wayHandling": 2,
"deletion": {
"softDeletionTags": {
"and": [
"razed:tourism:=information",
"tourism="
]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -180,5 +180,9 @@
], ],
"eraseInvalidValues": true "eraseInvalidValues": true
} }
] ],
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -81,5 +81,18 @@
"nl": "Voeg hier een parking voor auto's toe" "nl": "Voeg hier een parking voor auto's toe"
} }
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -101,5 +101,18 @@
} }
} }
], ],
"wayHandling": 1 "wayHandling": 1,
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -498,5 +498,18 @@
} }
] ]
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -115,5 +115,18 @@
"preferredBackground": "photo" "preferredBackground": "photo"
} }
} }
],
"deletion": {
"softDeletionTags": {
"and": [
"disused:amenity:={amenity}",
"amenity="
] ]
},
"neededChangesets": 1
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
}
} }

View file

@ -256,7 +256,6 @@
}, },
"move": { "move": {
"loginToMove": "You must be logged in to move a point", "loginToMove": "You must be logged in to move a point",
"inviteToMove": "Move this point",
"inviteToMoveAgain": "Move this point again", "inviteToMoveAgain": "Move this point again",
"moveTitle": "Move this point", "moveTitle": "Move this point",
"whyMove": "Why do you want to move this point?", "whyMove": "Why do you want to move this point?",
@ -264,8 +263,15 @@
"pointIsMoved": "The point has been moved", "pointIsMoved": "The point has been moved",
"zoomInFurther": "Zoom in further to confirm this move", "zoomInFurther": "Zoom in further to confirm this move",
"selectReason": "Why do you move this object?", "selectReason": "Why do you move this object?",
"reasons": {
"reasonRelocation": "The object has been relocated to a totally different location", "reasonRelocation": "The object has been relocated to a totally different location",
"reasonInaccurate": "The location of this object is inaccurate and should be moved a few meter", "reasonInaccurate": "The location of this object is inaccurate and should be moved a few meter"
},
"inviteToMove": {
"generic": "Move this point",
"reasonInaccurate": "Improve the accuracy of this point",
"reasonRelocation": "Move this object to a another place because it has relocated"
},
"cannotBeMoved": "This feature cannot be moved.", "cannotBeMoved": "This feature cannot be moved.",
"isWay": "This feature is a way. Use another OpenStreetMap editor to move it.", "isWay": "This feature is a way. Use another OpenStreetMap editor to move it.",
"isRelation": "This feature is a relation and can not be moved", "isRelation": "This feature is a relation and can not be moved",

View file

@ -7,7 +7,7 @@
"homepage": "https://mapcomplete.osm.be", "homepage": "https://mapcomplete.osm.be",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"increase-memory": "export NODE_OPTIONS=--max_old_space_size=6182", "increase-memory": "export NODE_OPTIONS=--max_old_space_size=8364",
"start": "npm run start:prepare && npm-run-all --parallel start:parallel:*", "start": "npm run start:prepare && npm-run-all --parallel start:parallel:*",
"strt": "npm run start:prepare && npm run start:parallel:parcel", "strt": "npm run start:prepare && npm run start:parallel:parcel",
"start:prepare": "ts-node scripts/generateLayerOverview.ts --no-fail && npm run increase-memory", "start:prepare": "ts-node scripts/generateLayerOverview.ts --no-fail && npm run increase-memory",

11
test.ts
View file

@ -2,6 +2,9 @@ import MoveWizard from "./UI/Popup/MoveWizard";
import State from "./State"; import State from "./State";
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts"; import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
import MinimapImplementation from "./UI/Base/MinimapImplementation"; import MinimapImplementation from "./UI/Base/MinimapImplementation";
import MoveConfig from "./Models/ThemeConfig/MoveConfig";
import {FixedUiElement} from "./UI/Base/FixedUiElement";
import Combine from "./UI/Base/Combine";
State.state = new State(AllKnownLayouts.allKnownLayouts.get("bookcases")) State.state = new State(AllKnownLayouts.allKnownLayouts.get("bookcases"))
@ -18,8 +21,14 @@ const feature = {
] ]
} }
} }
/*
MinimapImplementation.initialize() MinimapImplementation.initialize()
new MoveWizard( new MoveWizard(
feature, feature,
State.state).AttachTo("maindiv") State.state,
new MoveConfig({
enableRelocation: false,
enableImproveAccuracy: true
}, "test")).AttachTo("maindiv")
*/