From de5f8f95bb4bbc4d1827845e33c1140155f9a64c Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Thu, 1 Jul 2021 02:43:49 +0200 Subject: [PATCH] Hook deleteWizard into the specialVisualisations (WIP) --- Logic/Osm/DeleteAction.ts | 6 ++-- UI/Popup/DeleteWizard.ts | 5 +-- UI/SpecialVisualizations.ts | 71 ++++++++++++++++++++++++++++--------- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/Logic/Osm/DeleteAction.ts b/Logic/Osm/DeleteAction.ts index 5671504dd..73cb066df 100644 --- a/Logic/Osm/DeleteAction.ts +++ b/Logic/Osm/DeleteAction.ts @@ -10,10 +10,12 @@ export default class DeleteAction { public readonly canBeDeleted: UIEventSource<{ canBeDeleted?: boolean, reason: Translation }>; public readonly isDeleted = new UIEventSource(false); private readonly _id: string; + private readonly _allowDeletionAtChangesetCount: number; - constructor(id: string) { + constructor(id: string, allowDeletionAtChangesetCount?: number) { this._id = id; + this._allowDeletionAtChangesetCount = allowDeletionAtChangesetCount ?? Number.MAX_VALUE; this.canBeDeleted = new UIEventSource<{ canBeDeleted?: boolean; reason: Translation }>({ canBeDeleted: undefined, @@ -104,7 +106,7 @@ export default class DeleteAction { if (!ud.loggedIn) { return false; } - return ud.csCount >= Constants.userJourney.deletePointsOfOthersUnlock; + return ud.csCount >= Math.min(Constants.userJourney.deletePointsOfOthersUnlock, this._allowDeletionAtChangesetCount); }) const previousEditors = new UIEventSource(undefined) diff --git a/UI/Popup/DeleteWizard.ts b/UI/Popup/DeleteWizard.ts index 37f6efe5b..b5f5648ee 100644 --- a/UI/Popup/DeleteWizard.ts +++ b/UI/Popup/DeleteWizard.ts @@ -41,11 +41,12 @@ export default class DeleteWizard extends Toggle { constructor(id: string, options?: { noDeleteOptions?: { if: Tag[], then: Translation }[] - softDeletionTags?: Tag[] + softDeletionTags?: Tag[], + neededChangesets?: number }) { options = options ?? {} - const deleteAction = new DeleteAction(id); + const deleteAction = new DeleteAction(id, options.neededChangesets); const tagsSource = State.state.allElements.getEventSourceById(id) let softDeletionTags = options.softDeletionTags ?? [] diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index 447589c14..bdc65c23a 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -24,8 +24,10 @@ import Histogram from "./BigComponents/Histogram"; import Loc from "../Models/Loc"; import {Utils} from "../Utils"; import BaseLayer from "../Models/BaseLayer"; +import DeleteWizard from "./Popup/DeleteWizard"; +import Constants from "../Models/Constants"; -export interface SpecialVisualization{ +export interface SpecialVisualization { funcName: string, constr: ((state: State, tagSource: UIEventSource, argument: string[]) => BaseUIElement), docs: string, @@ -36,6 +38,14 @@ export interface SpecialVisualization{ export default class SpecialVisualizations { + public static specialVisualisationsByName: Map = SpecialVisualizations.byName(); + static HelpMessage: BaseUIElement = SpecialVisualizations.GenHelpMessage(); + static constructMiniMap: (options?: { + background?: UIEventSource, + location?: UIEventSource, + allowMoving?: boolean + }) => BaseUIElement; + static constructShowDataLayer: (features: UIEventSource<{ feature: any; freshness: Date }[]>, leafletMap: UIEventSource, layoutToUse: UIEventSource, enablePopups?: boolean, zoomToFeatures?: boolean) => any; public static specialVisualizations: SpecialVisualization[] = [ { @@ -137,7 +147,7 @@ export default class SpecialVisualizations { zoom = parsed; } } - const locationSource =new UIEventSource({ + const locationSource = new UIEventSource({ lat: Number(properties._lat), lon: Number(properties._lon), zoom: zoom @@ -149,9 +159,9 @@ export default class SpecialVisualizations { allowMoving: false } ) - + locationSource.addCallback(loc => { - if(loc.zoom > zoom){ + if (loc.zoom > zoom) { // We zoom back locationSource.data.zoom = zoom; locationSource.ping(); @@ -370,29 +380,56 @@ export default class SpecialVisualizations { [state.layoutToUse]) ) } + }, + { + funcName: "delete", + docs: `Offers a dialog to (soft) delete the point. The dialog is built to be user friendly and to prevent mistakes. If deletion is not possible, the dialog will hide itself. + +#### Hard deletion if enough experience + +A feature can only be deleted by mapcomplete if: + +- It is a node +- No ways or relations use the node +- The logged-in user has enough experience (at least ${Constants.userJourney.deletePointsOfOthersUnlock} changesets) OR the user is the only one to have edited the point previously +- The user did not select one of the 'non-delete-options' (see below) + +In all other cases, a 'soft deletion' is used. + +#### Soft deletion + +A 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore. +This makes it look like it was deleted, without doing damage. A fixme will be added to the point. + +Note that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme + +#### No-delete options + +In some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed "because the path is on their private property"). +However, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice "hey, there is a path missing here! Let me redraw it in OSM!) + +The correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore. +A no-delete option is offered as 'reason to delete it', but secretly retags. + +`, + args: [], + constr: (state, tagSource, args) => { + return new VariableUiElement(tagSource.map(tags => tags.id).map(id => + new DeleteWizard(id))) + } } ] - - private static byName() : Map{ + + private static byName(): Map { const result = new Map(); for (const specialVisualization of SpecialVisualizations.specialVisualizations) { result.set(specialVisualization.funcName, specialVisualization) } - + return result; } - - public static specialVisualisationsByName: Map = SpecialVisualizations.byName(); - - static HelpMessage: BaseUIElement = SpecialVisualizations.GenHelpMessage(); - static constructMiniMap: (options?: { - background?: UIEventSource, - location?: UIEventSource, - allowMoving?: boolean - }) => BaseUIElement; - static constructShowDataLayer: (features: UIEventSource<{ feature: any; freshness: Date }[]>, leafletMap: UIEventSource, layoutToUse: UIEventSource, enablePopups?: boolean, zoomToFeatures?: boolean) => any; private static GenHelpMessage() {