forked from MapComplete/MapComplete
Reformat all files with prettier
This commit is contained in:
parent
e22d189376
commit
b541d3eab4
382 changed files with 50893 additions and 35566 deletions
|
@ -1,48 +1,50 @@
|
|||
import BaseUIElement from "../BaseUIElement";
|
||||
import {SubtleButton} from "../Base/SubtleButton";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import Combine from "../Base/Combine";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Toggle from "../Input/Toggle";
|
||||
import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction";
|
||||
import Loading from "../Base/Loading";
|
||||
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
|
||||
import Lazy from "../Base/Lazy";
|
||||
import ConfirmLocationOfPoint from "../NewPoint/ConfirmLocationOfPoint";
|
||||
import Img from "../Base/Img";
|
||||
import FilteredLayer from "../../Models/FilteredLayer";
|
||||
import SpecialVisualizations from "../SpecialVisualizations";
|
||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
import Svg from "../../Svg";
|
||||
import {Utils} from "../../Utils";
|
||||
import Minimap from "../Base/Minimap";
|
||||
import ShowDataLayer from "../ShowDataLayer/ShowDataLayer";
|
||||
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource";
|
||||
import ShowDataMultiLayer from "../ShowDataLayer/ShowDataMultiLayer";
|
||||
import CreateWayWithPointReuseAction, {MergePointConfig} from "../../Logic/Osm/Actions/CreateWayWithPointReuseAction";
|
||||
import OsmChangeAction from "../../Logic/Osm/Actions/OsmChangeAction";
|
||||
import FeatureSource from "../../Logic/FeatureSource/FeatureSource";
|
||||
import {OsmObject, OsmWay} from "../../Logic/Osm/OsmObject";
|
||||
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState";
|
||||
import {DefaultGuiState} from "../DefaultGuiState";
|
||||
import {PresetInfo} from "../BigComponents/SimpleAddUI";
|
||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
import {And} from "../../Logic/Tags/And";
|
||||
import ReplaceGeometryAction from "../../Logic/Osm/Actions/ReplaceGeometryAction";
|
||||
import CreateMultiPolygonWithPointReuseAction from "../../Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction";
|
||||
import {Tag} from "../../Logic/Tags/Tag";
|
||||
import TagApplyButton from "./TagApplyButton";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
import * as conflation_json from "../../assets/layers/conflation/conflation.json";
|
||||
import {GeoOperations} from "../../Logic/GeoOperations";
|
||||
import {LoginToggle} from "./LoginButton";
|
||||
import {AutoAction} from "./AutoApplyButton";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
import {Changes} from "../../Logic/Osm/Changes";
|
||||
import {ElementStorage} from "../../Logic/ElementStorage";
|
||||
import Hash from "../../Logic/Web/Hash";
|
||||
import {PreciseInput} from "../../Models/ThemeConfig/PresetConfig";
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import { SubtleButton } from "../Base/SubtleButton"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import Combine from "../Base/Combine"
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Toggle from "../Input/Toggle"
|
||||
import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction"
|
||||
import Loading from "../Base/Loading"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import Lazy from "../Base/Lazy"
|
||||
import ConfirmLocationOfPoint from "../NewPoint/ConfirmLocationOfPoint"
|
||||
import Img from "../Base/Img"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import SpecialVisualizations from "../SpecialVisualizations"
|
||||
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||
import Svg from "../../Svg"
|
||||
import { Utils } from "../../Utils"
|
||||
import Minimap from "../Base/Minimap"
|
||||
import ShowDataLayer from "../ShowDataLayer/ShowDataLayer"
|
||||
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
|
||||
import ShowDataMultiLayer from "../ShowDataLayer/ShowDataMultiLayer"
|
||||
import CreateWayWithPointReuseAction, {
|
||||
MergePointConfig,
|
||||
} from "../../Logic/Osm/Actions/CreateWayWithPointReuseAction"
|
||||
import OsmChangeAction from "../../Logic/Osm/Actions/OsmChangeAction"
|
||||
import FeatureSource from "../../Logic/FeatureSource/FeatureSource"
|
||||
import { OsmObject, OsmWay } from "../../Logic/Osm/OsmObject"
|
||||
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"
|
||||
import { DefaultGuiState } from "../DefaultGuiState"
|
||||
import { PresetInfo } from "../BigComponents/SimpleAddUI"
|
||||
import { TagUtils } from "../../Logic/Tags/TagUtils"
|
||||
import { And } from "../../Logic/Tags/And"
|
||||
import ReplaceGeometryAction from "../../Logic/Osm/Actions/ReplaceGeometryAction"
|
||||
import CreateMultiPolygonWithPointReuseAction from "../../Logic/Osm/Actions/CreateMultiPolygonWithPointReuseAction"
|
||||
import { Tag } from "../../Logic/Tags/Tag"
|
||||
import TagApplyButton from "./TagApplyButton"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import * as conflation_json from "../../assets/layers/conflation/conflation.json"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import { LoginToggle } from "./LoginButton"
|
||||
import { AutoAction } from "./AutoApplyButton"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import { Changes } from "../../Logic/Osm/Changes"
|
||||
import { ElementStorage } from "../../Logic/ElementStorage"
|
||||
import Hash from "../../Logic/Web/Hash"
|
||||
import { PreciseInput } from "../../Models/ThemeConfig/PresetConfig"
|
||||
|
||||
/**
|
||||
* A helper class for the various import-flows.
|
||||
|
@ -52,14 +54,18 @@ abstract class AbstractImportButton implements SpecialVisualizations {
|
|||
protected static importedIds = new Set<string>()
|
||||
public readonly funcName: string
|
||||
public readonly docs: string
|
||||
public readonly args: { name: string, defaultValue?: string, doc: string }[]
|
||||
private readonly showRemovedTags: boolean;
|
||||
private readonly cannotBeImportedMessage: BaseUIElement | undefined;
|
||||
public readonly args: { name: string; defaultValue?: string; doc: string }[]
|
||||
private readonly showRemovedTags: boolean
|
||||
private readonly cannotBeImportedMessage: BaseUIElement | undefined
|
||||
|
||||
constructor(funcName: string, docsIntro: string, extraArgs: { name: string, doc: string, defaultValue?: string, required?: boolean }[],
|
||||
options?: {showRemovedTags? : true | boolean, cannotBeImportedMessage?: BaseUIElement}) {
|
||||
constructor(
|
||||
funcName: string,
|
||||
docsIntro: string,
|
||||
extraArgs: { name: string; doc: string; defaultValue?: string; required?: boolean }[],
|
||||
options?: { showRemovedTags?: true | boolean; cannotBeImportedMessage?: BaseUIElement }
|
||||
) {
|
||||
this.funcName = funcName
|
||||
this.showRemovedTags = options?.showRemovedTags ?? true;
|
||||
this.showRemovedTags = options?.showRemovedTags ?? true
|
||||
this.cannotBeImportedMessage = options?.cannotBeImportedMessage
|
||||
this.docs = `${docsIntro}
|
||||
|
||||
|
@ -77,34 +83,43 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
{
|
||||
name: "targetLayer",
|
||||
doc: "The id of the layer where this point should end up. This is not very strict, it will simply result in checking that this layer is shown preventing possible duplicate elements",
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "tags",
|
||||
doc: "The tags to add onto the new object - see specification above. If this is a key (a single word occuring in the properties of the object), the corresponding value is taken and expanded instead",
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "text",
|
||||
doc: "The text to show on the button",
|
||||
defaultValue: "Import this data into OpenStreetMap"
|
||||
defaultValue: "Import this data into OpenStreetMap",
|
||||
},
|
||||
{
|
||||
name: "icon",
|
||||
doc: "A nice icon to show in the button",
|
||||
defaultValue: "./assets/svg/addSmall.svg"
|
||||
defaultValue: "./assets/svg/addSmall.svg",
|
||||
},
|
||||
...extraArgs]
|
||||
|
||||
};
|
||||
|
||||
abstract constructElement(state: FeaturePipelineState,
|
||||
args: { max_snap_distance: string, snap_onto_layers: string, icon: string, text: string, tags: string, newTags: UIEventSource<any>, targetLayer: string },
|
||||
tagSource: UIEventSource<any>,
|
||||
guiState: DefaultGuiState,
|
||||
feature: any,
|
||||
onCancelClicked: () => void): BaseUIElement;
|
||||
...extraArgs,
|
||||
]
|
||||
}
|
||||
|
||||
abstract constructElement(
|
||||
state: FeaturePipelineState,
|
||||
args: {
|
||||
max_snap_distance: string
|
||||
snap_onto_layers: string
|
||||
icon: string
|
||||
text: string
|
||||
tags: string
|
||||
newTags: UIEventSource<any>
|
||||
targetLayer: string
|
||||
},
|
||||
tagSource: UIEventSource<any>,
|
||||
guiState: DefaultGuiState,
|
||||
feature: any,
|
||||
onCancelClicked: () => void
|
||||
): BaseUIElement
|
||||
|
||||
constr(state, tagSource: UIEventSource<any>, argsRaw, guiState) {
|
||||
/**
|
||||
|
@ -116,16 +131,25 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
* The actual import flow (showing the conflation map, special cases) are handled in 'constructElement'
|
||||
*/
|
||||
|
||||
const t = Translations.t.general.add.import;
|
||||
const t0 = Translations.t.general.add;
|
||||
const t = Translations.t.general.add.import
|
||||
const t0 = Translations.t.general.add
|
||||
const args = this.parseArgs(argsRaw, tagSource)
|
||||
|
||||
{
|
||||
// Some initial validation
|
||||
if (!state.layoutToUse.official && !(state.featureSwitchIsTesting.data || state.osmConnection._oauth_config.url === OsmConnection.oauth_configs["osm-test"].url)) {
|
||||
if (
|
||||
!state.layoutToUse.official &&
|
||||
!(
|
||||
state.featureSwitchIsTesting.data ||
|
||||
state.osmConnection._oauth_config.url ===
|
||||
OsmConnection.oauth_configs["osm-test"].url
|
||||
)
|
||||
) {
|
||||
return new Combine([t.officialThemesOnly.SetClass("alert"), t.howToTest])
|
||||
}
|
||||
const targetLayer: FilteredLayer = state.filteredLayers.data.filter(fl => fl.layerDef.id === args.targetLayer)[0]
|
||||
const targetLayer: FilteredLayer = state.filteredLayers.data.filter(
|
||||
(fl) => fl.layerDef.id === args.targetLayer
|
||||
)[0]
|
||||
if (targetLayer === undefined) {
|
||||
const e = `Target layer not defined: error in import button for theme: ${state.layoutToUse.id}: layer ${args.targetLayer} not found`
|
||||
console.error(e)
|
||||
|
@ -133,7 +157,6 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
let img: BaseUIElement
|
||||
if (args.icon !== undefined && args.icon !== "") {
|
||||
img = new Img(args.icon)
|
||||
|
@ -142,41 +165,54 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
}
|
||||
const inviteToImportButton = new SubtleButton(img, args.text)
|
||||
|
||||
const id = tagSource.data.id;
|
||||
const id = tagSource.data.id
|
||||
const feature = state.allElements.ContainingFeatures.get(id)
|
||||
|
||||
|
||||
// Explanation of the tags that will be applied onto the imported/conflated object
|
||||
|
||||
let tagSpec = args.tags;
|
||||
if (tagSpec.indexOf(" ") < 0 && tagSpec.indexOf(";") < 0 && tagSource.data[args.tags] !== undefined) {
|
||||
let tagSpec = args.tags
|
||||
if (
|
||||
tagSpec.indexOf(" ") < 0 &&
|
||||
tagSpec.indexOf(";") < 0 &&
|
||||
tagSource.data[args.tags] !== undefined
|
||||
) {
|
||||
// This is probably a key
|
||||
tagSpec = tagSource.data[args.tags]
|
||||
console.debug("The import button is using tags from properties[" + args.tags + "] of this object, namely ", tagSpec)
|
||||
console.debug(
|
||||
"The import button is using tags from properties[" +
|
||||
args.tags +
|
||||
"] of this object, namely ",
|
||||
tagSpec
|
||||
)
|
||||
}
|
||||
|
||||
const importClicked = new UIEventSource(false);
|
||||
const importClicked = new UIEventSource(false)
|
||||
inviteToImportButton.onClick(() => {
|
||||
importClicked.setData(true);
|
||||
importClicked.setData(true)
|
||||
})
|
||||
|
||||
|
||||
const pleaseLoginButton = new Toggle(t0.pleaseLogin
|
||||
const pleaseLoginButton = new Toggle(
|
||||
t0.pleaseLogin
|
||||
.onClick(() => state.osmConnection.AttemptLogin())
|
||||
.SetClass("login-button-friendly"),
|
||||
undefined,
|
||||
state.featureSwitchUserbadge)
|
||||
state.featureSwitchUserbadge
|
||||
)
|
||||
|
||||
|
||||
const isImported = tagSource.map(tags => {
|
||||
const isImported = tagSource.map((tags) => {
|
||||
AbstractImportButton.importedIds.add(tags.id)
|
||||
return tags._imported === "yes";
|
||||
return tags._imported === "yes"
|
||||
})
|
||||
|
||||
|
||||
/**** THe actual panel showing the import guiding map ****/
|
||||
const importGuidingPanel = this.constructElement(state, args, tagSource, guiState, feature, () => importClicked.setData(false))
|
||||
|
||||
const importGuidingPanel = this.constructElement(
|
||||
state,
|
||||
args,
|
||||
tagSource,
|
||||
guiState,
|
||||
feature,
|
||||
() => importClicked.setData(false)
|
||||
)
|
||||
|
||||
const importFlow = new Toggle(
|
||||
new Toggle(
|
||||
|
@ -186,25 +222,21 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
),
|
||||
inviteToImportButton,
|
||||
importClicked
|
||||
);
|
||||
)
|
||||
|
||||
return new Toggle(
|
||||
new LoginToggle(
|
||||
new Toggle(
|
||||
new Toggle(
|
||||
t.hasBeenImported,
|
||||
importFlow,
|
||||
isImported
|
||||
),
|
||||
new Toggle(t.hasBeenImported, importFlow, isImported),
|
||||
t.zoomInMore.SetClass("alert block"),
|
||||
state.locationControl.map(l => l.zoom >= 18)
|
||||
state.locationControl.map((l) => l.zoom >= 18)
|
||||
),
|
||||
pleaseLoginButton,
|
||||
state
|
||||
),
|
||||
this.cannotBeImportedMessage ?? t.wrongType,
|
||||
new UIEventSource(this.canBeImported(feature)))
|
||||
|
||||
new UIEventSource(this.canBeImported(feature))
|
||||
)
|
||||
}
|
||||
|
||||
getLayerDependencies(argsRaw: string[]) {
|
||||
|
@ -215,7 +247,7 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
// The target layer
|
||||
dependsOnLayers.push(args.targetLayer)
|
||||
|
||||
const snapOntoLayers = args.snap_onto_layers?.trim() ?? "";
|
||||
const snapOntoLayers = args.snap_onto_layers?.trim() ?? ""
|
||||
if (snapOntoLayers !== "") {
|
||||
dependsOnLayers.push(...snapOntoLayers.split(";"))
|
||||
}
|
||||
|
@ -227,15 +259,23 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
|
||||
protected createConfirmPanelForWay(
|
||||
state: FeaturePipelineState,
|
||||
args: { max_snap_distance: string, snap_onto_layers: string, icon: string, text: string, newTags: UIEventSource<Tag[]>, targetLayer: string },
|
||||
args: {
|
||||
max_snap_distance: string
|
||||
snap_onto_layers: string
|
||||
icon: string
|
||||
text: string
|
||||
newTags: UIEventSource<Tag[]>
|
||||
targetLayer: string
|
||||
},
|
||||
feature: any,
|
||||
originalFeatureTags: UIEventSource<any>,
|
||||
action: (OsmChangeAction & { getPreview(): Promise<FeatureSource>, newElementId?: string }),
|
||||
onCancel: () => void): BaseUIElement {
|
||||
const self = this;
|
||||
action: OsmChangeAction & { getPreview(): Promise<FeatureSource>; newElementId?: string },
|
||||
onCancel: () => void
|
||||
): BaseUIElement {
|
||||
const self = this
|
||||
const confirmationMap = Minimap.createMiniMap({
|
||||
allowMoving: state.featureSwitchIsDebugging.data ?? false,
|
||||
background: state.backgroundLayer
|
||||
background: state.backgroundLayer,
|
||||
})
|
||||
confirmationMap.SetStyle("height: 20rem; overflow: hidden").SetClass("rounded-xl")
|
||||
|
||||
|
@ -245,28 +285,33 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
zoomToFeatures: true,
|
||||
features: StaticFeatureSource.fromGeojson([feature]),
|
||||
state: state,
|
||||
layers: state.filteredLayers
|
||||
layers: state.filteredLayers,
|
||||
})
|
||||
|
||||
|
||||
action.getPreview().then(changePreview => {
|
||||
action.getPreview().then((changePreview) => {
|
||||
new ShowDataLayer({
|
||||
leafletMap: confirmationMap.leafletMap,
|
||||
zoomToFeatures: false,
|
||||
features: changePreview,
|
||||
state,
|
||||
layerToShow: new LayerConfig(conflation_json, "all_known_layers", true)
|
||||
layerToShow: new LayerConfig(conflation_json, "all_known_layers", true),
|
||||
})
|
||||
})
|
||||
|
||||
const tagsExplanation = new VariableUiElement(args.newTags.map(tagsToApply => {
|
||||
const filteredTags = tagsToApply.filter(t => self.showRemovedTags || (t.value ?? "") !== "")
|
||||
const tagsExplanation = new VariableUiElement(
|
||||
args.newTags.map((tagsToApply) => {
|
||||
const filteredTags = tagsToApply.filter(
|
||||
(t) => self.showRemovedTags || (t.value ?? "") !== ""
|
||||
)
|
||||
const tagsStr = new And(filteredTags).asHumanString(false, true, {})
|
||||
return Translations.t.general.add.import.importTags.Subs({tags: tagsStr});
|
||||
}
|
||||
)).SetClass("subtle")
|
||||
return Translations.t.general.add.import.importTags.Subs({ tags: tagsStr })
|
||||
})
|
||||
).SetClass("subtle")
|
||||
|
||||
const confirmButton = new SubtleButton(new Img(args.icon), new Combine([args.text, tagsExplanation]).SetClass("flex flex-col"))
|
||||
const confirmButton = new SubtleButton(
|
||||
new Img(args.icon),
|
||||
new Combine([args.text, tagsExplanation]).SetClass("flex flex-col")
|
||||
)
|
||||
confirmButton.onClick(async () => {
|
||||
{
|
||||
originalFeatureTags.data["_imported"] = "yes"
|
||||
|
@ -277,19 +322,41 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
}
|
||||
})
|
||||
|
||||
const cancel = new SubtleButton(Svg.close_ui(), Translations.t.general.cancel).onClick(onCancel)
|
||||
const cancel = new SubtleButton(Svg.close_ui(), Translations.t.general.cancel).onClick(
|
||||
onCancel
|
||||
)
|
||||
return new Combine([confirmationMap, confirmButton, cancel]).SetClass("flex flex-col")
|
||||
}
|
||||
|
||||
protected parseArgs(argsRaw: string[], originalFeatureTags: UIEventSource<any>): { minzoom: string, max_snap_distance: string, snap_onto_layers: string, icon: string, text: string, tags: string, targetLayer: string, newTags: UIEventSource<Tag[]> } {
|
||||
protected parseArgs(
|
||||
argsRaw: string[],
|
||||
originalFeatureTags: UIEventSource<any>
|
||||
): {
|
||||
minzoom: string
|
||||
max_snap_distance: string
|
||||
snap_onto_layers: string
|
||||
icon: string
|
||||
text: string
|
||||
tags: string
|
||||
targetLayer: string
|
||||
newTags: UIEventSource<Tag[]>
|
||||
} {
|
||||
const baseArgs = Utils.ParseVisArgs(this.args, argsRaw)
|
||||
if (originalFeatureTags !== undefined) {
|
||||
|
||||
const tags = baseArgs.tags
|
||||
if (tags.indexOf(" ") < 0 && tags.indexOf(";") < 0 && originalFeatureTags.data[tags] !== undefined) {
|
||||
if (
|
||||
tags.indexOf(" ") < 0 &&
|
||||
tags.indexOf(";") < 0 &&
|
||||
originalFeatureTags.data[tags] !== undefined
|
||||
) {
|
||||
// This might be a property to expand...
|
||||
const items: string = originalFeatureTags.data[tags]
|
||||
console.debug("The import button is using tags from properties[" + tags + "] of this object, namely ", items)
|
||||
console.debug(
|
||||
"The import button is using tags from properties[" +
|
||||
tags +
|
||||
"] of this object, namely ",
|
||||
items
|
||||
)
|
||||
baseArgs["newTags"] = TagApplyButton.generateTagsToApply(items, originalFeatureTags)
|
||||
} else {
|
||||
baseArgs["newTags"] = TagApplyButton.generateTagsToApply(tags, originalFeatureTags)
|
||||
|
@ -300,55 +367,66 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
}
|
||||
|
||||
export class ConflateButton extends AbstractImportButton {
|
||||
|
||||
constructor() {
|
||||
super("conflate_button", "This button will modify the geometry of an existing OSM way to match the specified geometry. This can conflate OSM-ways with LineStrings and Polygons (only simple polygons with one single ring). An attempt is made to move points with special values to a decent new location (e.g. entrances)",
|
||||
[{
|
||||
name: "way_to_conflate",
|
||||
doc: "The key, of which the corresponding value is the id of the OSM-way that must be conflated; typically a calculatedTag"
|
||||
}],
|
||||
super(
|
||||
"conflate_button",
|
||||
"This button will modify the geometry of an existing OSM way to match the specified geometry. This can conflate OSM-ways with LineStrings and Polygons (only simple polygons with one single ring). An attempt is made to move points with special values to a decent new location (e.g. entrances)",
|
||||
[
|
||||
{
|
||||
name: "way_to_conflate",
|
||||
doc: "The key, of which the corresponding value is the id of the OSM-way that must be conflated; typically a calculatedTag",
|
||||
},
|
||||
],
|
||||
{
|
||||
cannotBeImportedMessage: Translations.t.general.add.import.wrongTypeToConflate
|
||||
cannotBeImportedMessage: Translations.t.general.add.import.wrongTypeToConflate,
|
||||
}
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
getLayerDependencies(argsRaw: string[]): string[] {
|
||||
const deps = super.getLayerDependencies(argsRaw);
|
||||
const deps = super.getLayerDependencies(argsRaw)
|
||||
// Force 'type_node' as dependency
|
||||
deps.push("type_node")
|
||||
return deps;
|
||||
return deps
|
||||
}
|
||||
|
||||
constructElement(state: FeaturePipelineState,
|
||||
args: { max_snap_distance: string; snap_onto_layers: string; icon: string; text: string; tags: string; newTags: UIEventSource<Tag[]>; targetLayer: string },
|
||||
tagSource: UIEventSource<any>, guiState: DefaultGuiState, feature: any, onCancelClicked: () => void): BaseUIElement {
|
||||
|
||||
const nodesMustMatch = args.snap_onto_layers?.split(";")?.map((tag, i) => TagUtils.Tag(tag, "TagsSpec for import button " + i))
|
||||
constructElement(
|
||||
state: FeaturePipelineState,
|
||||
args: {
|
||||
max_snap_distance: string
|
||||
snap_onto_layers: string
|
||||
icon: string
|
||||
text: string
|
||||
tags: string
|
||||
newTags: UIEventSource<Tag[]>
|
||||
targetLayer: string
|
||||
},
|
||||
tagSource: UIEventSource<any>,
|
||||
guiState: DefaultGuiState,
|
||||
feature: any,
|
||||
onCancelClicked: () => void
|
||||
): BaseUIElement {
|
||||
const nodesMustMatch = args.snap_onto_layers
|
||||
?.split(";")
|
||||
?.map((tag, i) => TagUtils.Tag(tag, "TagsSpec for import button " + i))
|
||||
|
||||
const mergeConfigs = []
|
||||
if (nodesMustMatch !== undefined && nodesMustMatch.length > 0) {
|
||||
const mergeConfig: MergePointConfig = {
|
||||
mode: args["point_move_mode"] == "move_osm" ? "move_osm_point" : "reuse_osm_point",
|
||||
ifMatches: new And(nodesMustMatch),
|
||||
withinRangeOfM: Number(args.max_snap_distance)
|
||||
withinRangeOfM: Number(args.max_snap_distance),
|
||||
}
|
||||
mergeConfigs.push(mergeConfig)
|
||||
}
|
||||
|
||||
|
||||
const key = args["way_to_conflate"]
|
||||
const wayToConflate = tagSource.data[key]
|
||||
feature = GeoOperations.removeOvernoding(feature);
|
||||
const action = new ReplaceGeometryAction(
|
||||
state,
|
||||
feature,
|
||||
wayToConflate,
|
||||
{
|
||||
theme: state.layoutToUse.id,
|
||||
newTags: args.newTags.data
|
||||
}
|
||||
)
|
||||
feature = GeoOperations.removeOvernoding(feature)
|
||||
const action = new ReplaceGeometryAction(state, feature, wayToConflate, {
|
||||
theme: state.layoutToUse.id,
|
||||
newTags: args.newTags.data,
|
||||
})
|
||||
|
||||
return this.createConfirmPanelForWay(
|
||||
state,
|
||||
|
@ -361,16 +439,19 @@ export class ConflateButton extends AbstractImportButton {
|
|||
}
|
||||
|
||||
protected canBeImported(feature: any) {
|
||||
return feature.geometry.type === "LineString" || (feature.geometry.type === "Polygon" && feature.geometry.coordinates.length === 1)
|
||||
return (
|
||||
feature.geometry.type === "LineString" ||
|
||||
(feature.geometry.type === "Polygon" && feature.geometry.coordinates.length === 1)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ImportWayButton extends AbstractImportButton implements AutoAction {
|
||||
public readonly supportsAutoAction = true;
|
||||
public readonly supportsAutoAction = true
|
||||
|
||||
constructor() {
|
||||
super("import_way_button",
|
||||
super(
|
||||
"import_way_button",
|
||||
"This button will copy the data from an external dataset into OpenStreetMap",
|
||||
[
|
||||
{
|
||||
|
@ -380,34 +461,47 @@ export class ImportWayButton extends AbstractImportButton implements AutoAction
|
|||
{
|
||||
name: "max_snap_distance",
|
||||
doc: "If the imported object is a LineString or (Multi)Polygon, already existing OSM-points will be reused to construct the geometry of the newly imported way",
|
||||
defaultValue: "0.05"
|
||||
defaultValue: "0.05",
|
||||
},
|
||||
{
|
||||
name: "move_osm_point_if",
|
||||
doc: "Moves the OSM-point to the newly imported point if these conditions are met",
|
||||
}, {
|
||||
name: "max_move_distance",
|
||||
doc: "If an OSM-point is moved, the maximum amount of meters it is moved. Capped on 20m",
|
||||
defaultValue: "0.05"
|
||||
}, {
|
||||
name: "snap_onto_layers",
|
||||
doc: "If no existing nearby point exists, but a line of a specified layer is closeby, snap to this layer instead",
|
||||
|
||||
}, {
|
||||
name: "snap_to_layer_max_distance",
|
||||
doc: "Distance to distort the geometry to snap to this layer",
|
||||
defaultValue: "0.1"
|
||||
}],
|
||||
{ showRemovedTags: false}
|
||||
},
|
||||
{
|
||||
name: "max_move_distance",
|
||||
doc: "If an OSM-point is moved, the maximum amount of meters it is moved. Capped on 20m",
|
||||
defaultValue: "0.05",
|
||||
},
|
||||
{
|
||||
name: "snap_onto_layers",
|
||||
doc: "If no existing nearby point exists, but a line of a specified layer is closeby, snap to this layer instead",
|
||||
},
|
||||
{
|
||||
name: "snap_to_layer_max_distance",
|
||||
doc: "Distance to distort the geometry to snap to this layer",
|
||||
defaultValue: "0.1",
|
||||
},
|
||||
],
|
||||
{ showRemovedTags: false }
|
||||
)
|
||||
}
|
||||
|
||||
private static CreateAction(feature,
|
||||
args: { max_snap_distance: string; snap_onto_layers: string; icon: string; text: string; tags: string; newTags: UIEventSource<any>; targetLayer: string },
|
||||
state: FeaturePipelineState,
|
||||
mergeConfigs: any[]) {
|
||||
private static CreateAction(
|
||||
feature,
|
||||
args: {
|
||||
max_snap_distance: string
|
||||
snap_onto_layers: string
|
||||
icon: string
|
||||
text: string
|
||||
tags: string
|
||||
newTags: UIEventSource<any>
|
||||
targetLayer: string
|
||||
},
|
||||
state: FeaturePipelineState,
|
||||
mergeConfigs: any[]
|
||||
) {
|
||||
const coors = feature.geometry.coordinates
|
||||
if ((feature.geometry.type === "Polygon") && coors.length > 1) {
|
||||
if (feature.geometry.type === "Polygon" && coors.length > 1) {
|
||||
const outer = coors[0]
|
||||
const inner = [...coors]
|
||||
inner.splice(0, 1)
|
||||
|
@ -421,36 +515,27 @@ export class ImportWayButton extends AbstractImportButton implements AutoAction
|
|||
)
|
||||
} else if (feature.geometry.type === "Polygon") {
|
||||
const outer = coors[0]
|
||||
return new CreateWayWithPointReuseAction(
|
||||
args.newTags.data,
|
||||
outer,
|
||||
state,
|
||||
mergeConfigs
|
||||
)
|
||||
return new CreateWayWithPointReuseAction(args.newTags.data, outer, state, mergeConfigs)
|
||||
} else if (feature.geometry.type === "LineString") {
|
||||
return new CreateWayWithPointReuseAction(
|
||||
args.newTags.data,
|
||||
coors,
|
||||
state,
|
||||
mergeConfigs
|
||||
)
|
||||
return new CreateWayWithPointReuseAction(args.newTags.data, coors, state, mergeConfigs)
|
||||
} else {
|
||||
throw "Unsupported type"
|
||||
}
|
||||
}
|
||||
|
||||
async applyActionOn(state: { layoutToUse: LayoutConfig; changes: Changes, allElements: ElementStorage },
|
||||
originalFeatureTags: UIEventSource<any>,
|
||||
argument: string[]): Promise<void> {
|
||||
const id = originalFeatureTags.data.id;
|
||||
if (AbstractImportButton.importedIds.has(originalFeatureTags.data.id)
|
||||
) {
|
||||
return;
|
||||
async applyActionOn(
|
||||
state: { layoutToUse: LayoutConfig; changes: Changes; allElements: ElementStorage },
|
||||
originalFeatureTags: UIEventSource<any>,
|
||||
argument: string[]
|
||||
): Promise<void> {
|
||||
const id = originalFeatureTags.data.id
|
||||
if (AbstractImportButton.importedIds.has(originalFeatureTags.data.id)) {
|
||||
return
|
||||
}
|
||||
AbstractImportButton.importedIds.add(originalFeatureTags.data.id)
|
||||
const args = this.parseArgs(argument, originalFeatureTags)
|
||||
const feature = state.allElements.ContainingFeatures.get(id)
|
||||
const mergeConfigs = this.GetMergeConfig(args);
|
||||
const mergeConfigs = this.GetMergeConfig(args)
|
||||
const action = ImportWayButton.CreateAction(
|
||||
feature,
|
||||
args,
|
||||
|
@ -466,18 +551,12 @@ export class ImportWayButton extends AbstractImportButton implements AutoAction
|
|||
}
|
||||
|
||||
getLayerDependencies(argsRaw: string[]): string[] {
|
||||
const deps = super.getLayerDependencies(argsRaw);
|
||||
const deps = super.getLayerDependencies(argsRaw)
|
||||
deps.push("type_node")
|
||||
return deps
|
||||
}
|
||||
|
||||
constructElement(state, args,
|
||||
originalFeatureTags,
|
||||
guiState,
|
||||
feature,
|
||||
onCancel): BaseUIElement {
|
||||
|
||||
|
||||
constructElement(state, args, originalFeatureTags, guiState, feature, onCancel): BaseUIElement {
|
||||
const geometry = feature.geometry
|
||||
|
||||
if (!(geometry.type == "LineString" || geometry.type === "Polygon")) {
|
||||
|
@ -485,10 +564,9 @@ export class ImportWayButton extends AbstractImportButton implements AutoAction
|
|||
return new FixedUiElement("Invalid geometry type:" + geometry.type).SetClass("alert")
|
||||
}
|
||||
|
||||
|
||||
// Upload the way to OSM
|
||||
const mergeConfigs = this.GetMergeConfig(args);
|
||||
let action = ImportWayButton.CreateAction(feature, args, state, mergeConfigs);
|
||||
const mergeConfigs = this.GetMergeConfig(args)
|
||||
let action = ImportWayButton.CreateAction(feature, args, state, mergeConfigs)
|
||||
return this.createConfirmPanelForWay(
|
||||
state,
|
||||
args,
|
||||
|
@ -497,83 +575,105 @@ export class ImportWayButton extends AbstractImportButton implements AutoAction
|
|||
action,
|
||||
onCancel
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private GetMergeConfig(args: { max_snap_distance: string; snap_onto_layers: string; icon: string; text: string; tags: string; newTags: UIEventSource<any>; targetLayer: string })
|
||||
: MergePointConfig[] {
|
||||
const nodesMustMatch = args["snap_to_point_if"]?.split(";")?.map((tag, i) => TagUtils.Tag(tag, "TagsSpec for import button " + i))
|
||||
private GetMergeConfig(args: {
|
||||
max_snap_distance: string
|
||||
snap_onto_layers: string
|
||||
icon: string
|
||||
text: string
|
||||
tags: string
|
||||
newTags: UIEventSource<any>
|
||||
targetLayer: string
|
||||
}): MergePointConfig[] {
|
||||
const nodesMustMatch = args["snap_to_point_if"]
|
||||
?.split(";")
|
||||
?.map((tag, i) => TagUtils.Tag(tag, "TagsSpec for import button " + i))
|
||||
|
||||
const mergeConfigs = []
|
||||
if (nodesMustMatch !== undefined && nodesMustMatch.length > 0) {
|
||||
const mergeConfig: MergePointConfig = {
|
||||
mode: "reuse_osm_point",
|
||||
ifMatches: new And(nodesMustMatch),
|
||||
withinRangeOfM: Number(args.max_snap_distance)
|
||||
withinRangeOfM: Number(args.max_snap_distance),
|
||||
}
|
||||
mergeConfigs.push(mergeConfig)
|
||||
}
|
||||
|
||||
|
||||
const moveOsmPointIfTags = args["move_osm_point_if"]?.split(";")?.map((tag, i) => TagUtils.Tag(tag, "TagsSpec for import button " + i))
|
||||
const moveOsmPointIfTags = args["move_osm_point_if"]
|
||||
?.split(";")
|
||||
?.map((tag, i) => TagUtils.Tag(tag, "TagsSpec for import button " + i))
|
||||
|
||||
if (nodesMustMatch !== undefined && moveOsmPointIfTags.length > 0) {
|
||||
const moveDistance = Math.min(20, Number(args["max_move_distance"]))
|
||||
const mergeConfig: MergePointConfig = {
|
||||
mode: "move_osm_point",
|
||||
ifMatches: new And(moveOsmPointIfTags),
|
||||
withinRangeOfM: moveDistance
|
||||
withinRangeOfM: moveDistance,
|
||||
}
|
||||
mergeConfigs.push(mergeConfig)
|
||||
}
|
||||
|
||||
return mergeConfigs;
|
||||
return mergeConfigs
|
||||
}
|
||||
}
|
||||
|
||||
export class ImportPointButton extends AbstractImportButton {
|
||||
|
||||
constructor() {
|
||||
super("import_button",
|
||||
super(
|
||||
"import_button",
|
||||
"This button will copy the point from an external dataset into OpenStreetMap",
|
||||
[
|
||||
{
|
||||
name: "snap_onto_layers",
|
||||
doc: "If a way of the given layer(s) is closeby, will snap the new point onto this way (similar as preset might snap). To show multiple layers to snap onto, use a `;`-seperated list"
|
||||
doc: "If a way of the given layer(s) is closeby, will snap the new point onto this way (similar as preset might snap). To show multiple layers to snap onto, use a `;`-seperated list",
|
||||
},
|
||||
{
|
||||
name: "max_snap_distance",
|
||||
doc: "The maximum distance that the imported point will be moved to snap onto a way in an already existing layer (in meters). This is previewed to the contributor, similar to the 'add new point'-action of MapComplete",
|
||||
defaultValue: "5"
|
||||
defaultValue: "5",
|
||||
},
|
||||
{
|
||||
name: "note_id",
|
||||
doc: "If given, this key will be read. The corresponding note on OSM will be closed, stating 'imported'"
|
||||
doc: "If given, this key will be read. The corresponding note on OSM will be closed, stating 'imported'",
|
||||
},
|
||||
{
|
||||
name:"location_picker",
|
||||
name: "location_picker",
|
||||
defaultValue: "photo",
|
||||
doc: "Chooses the background for the precise location picker, options are 'map', 'photo' or 'osmbasedmap' or 'none' if the precise input picker should be disabled"
|
||||
doc: "Chooses the background for the precise location picker, options are 'map', 'photo' or 'osmbasedmap' or 'none' if the precise input picker should be disabled",
|
||||
},
|
||||
{
|
||||
name: "maproulette_id",
|
||||
doc: "If given, the maproulette challenge will be marked as fixed"
|
||||
}],
|
||||
{ showRemovedTags: false}
|
||||
doc: "If given, the maproulette challenge will be marked as fixed",
|
||||
},
|
||||
],
|
||||
{ showRemovedTags: false }
|
||||
)
|
||||
}
|
||||
|
||||
private static createConfirmPanelForPoint(
|
||||
args: { max_snap_distance: string, snap_onto_layers: string, icon: string, text: string, newTags: UIEventSource<any>, targetLayer: string, note_id: string, maproulette_id: string },
|
||||
args: {
|
||||
max_snap_distance: string
|
||||
snap_onto_layers: string
|
||||
icon: string
|
||||
text: string
|
||||
newTags: UIEventSource<any>
|
||||
targetLayer: string
|
||||
note_id: string
|
||||
maproulette_id: string
|
||||
},
|
||||
state: FeaturePipelineState,
|
||||
guiState: DefaultGuiState,
|
||||
originalFeatureTags: UIEventSource<any>,
|
||||
feature: any,
|
||||
onCancel: () => void,
|
||||
close: () => void): BaseUIElement {
|
||||
|
||||
async function confirm(tags: any[], location: { lat: number, lon: number }, snapOntoWayId: string) {
|
||||
|
||||
close: () => void
|
||||
): BaseUIElement {
|
||||
async function confirm(
|
||||
tags: any[],
|
||||
location: { lat: number; lon: number },
|
||||
snapOntoWayId: string
|
||||
) {
|
||||
originalFeatureTags.data["_imported"] = "yes"
|
||||
originalFeatureTags.ping() // will set isImported as per its definition
|
||||
let snapOnto: OsmObject = undefined
|
||||
|
@ -592,13 +692,13 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
theme: state.layoutToUse.id,
|
||||
changeType: "import",
|
||||
snapOnto: <OsmWay>snapOnto,
|
||||
specialMotivation: specialMotivation
|
||||
specialMotivation: specialMotivation,
|
||||
})
|
||||
|
||||
await state.changes.applyAction(newElementAction)
|
||||
state.selectedElement.setData(state.allElements.ContainingFeatures.get(
|
||||
newElementAction.newElementId
|
||||
))
|
||||
state.selectedElement.setData(
|
||||
state.allElements.ContainingFeatures.get(newElementAction.newElementId)
|
||||
)
|
||||
Hash.hash.setData(newElementAction.newElementId)
|
||||
|
||||
if (note_id !== undefined) {
|
||||
|
@ -607,47 +707,63 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
originalFeatureTags.ping()
|
||||
}
|
||||
|
||||
let maproulette_id = originalFeatureTags.data[args.maproulette_id];
|
||||
console.log("Checking if we need to mark a maproulette task as fixed (" + maproulette_id + ")")
|
||||
let maproulette_id = originalFeatureTags.data[args.maproulette_id]
|
||||
console.log(
|
||||
"Checking if we need to mark a maproulette task as fixed (" + maproulette_id + ")"
|
||||
)
|
||||
if (maproulette_id !== undefined) {
|
||||
if (state.featureSwitchIsTesting.data){
|
||||
console.log("Not marking maproulette task " + maproulette_id + " as fixed, because we are in testing mode")
|
||||
if (state.featureSwitchIsTesting.data) {
|
||||
console.log(
|
||||
"Not marking maproulette task " +
|
||||
maproulette_id +
|
||||
" as fixed, because we are in testing mode"
|
||||
)
|
||||
} else {
|
||||
console.log("Marking maproulette task as fixed")
|
||||
state.maprouletteConnection.closeTask(Number(maproulette_id));
|
||||
originalFeatureTags.data["mr_taskStatus"] = "Fixed";
|
||||
originalFeatureTags.ping();
|
||||
state.maprouletteConnection.closeTask(Number(maproulette_id))
|
||||
originalFeatureTags.data["mr_taskStatus"] = "Fixed"
|
||||
originalFeatureTags.ping()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let preciseInputOption = args["location_picker"]
|
||||
let preciseInputSpec: PreciseInput = undefined
|
||||
let preciseInputSpec: PreciseInput = undefined
|
||||
console.log("Precise input location is ", preciseInputOption)
|
||||
if(preciseInputOption !== "none") {
|
||||
if (preciseInputOption !== "none") {
|
||||
preciseInputSpec = {
|
||||
snapToLayers: args.snap_onto_layers?.split(";"),
|
||||
maxSnapDistance: Number(args.max_snap_distance),
|
||||
preferredBackground: args["location_picker"] ?? ["photo", "map"]
|
||||
maxSnapDistance: Number(args.max_snap_distance),
|
||||
preferredBackground: args["location_picker"] ?? ["photo", "map"],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const presetInfo = <PresetInfo>{
|
||||
tags: args.newTags.data,
|
||||
icon: () => new Img(args.icon),
|
||||
layerToAddTo: state.filteredLayers.data.filter(l => l.layerDef.id === args.targetLayer)[0],
|
||||
layerToAddTo: state.filteredLayers.data.filter(
|
||||
(l) => l.layerDef.id === args.targetLayer
|
||||
)[0],
|
||||
name: args.text,
|
||||
title: Translations.T(args.text),
|
||||
preciseInput: preciseInputSpec, // must be explicitely assigned, if 'undefined' won't work otherwise
|
||||
boundsFactor: 3
|
||||
boundsFactor: 3,
|
||||
}
|
||||
|
||||
const [lon, lat] = feature.geometry.coordinates
|
||||
return new ConfirmLocationOfPoint(state, guiState.filterViewIsOpened, presetInfo, Translations.W(args.text), {
|
||||
lon,
|
||||
lat
|
||||
}, confirm, onCancel, close)
|
||||
|
||||
return new ConfirmLocationOfPoint(
|
||||
state,
|
||||
guiState.filterViewIsOpened,
|
||||
presetInfo,
|
||||
Translations.W(args.text),
|
||||
{
|
||||
lon,
|
||||
lat,
|
||||
},
|
||||
confirm,
|
||||
onCancel,
|
||||
close
|
||||
)
|
||||
}
|
||||
|
||||
canBeImported(feature: any) {
|
||||
|
@ -655,7 +771,7 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
}
|
||||
|
||||
getLayerDependencies(argsRaw: string[]): string[] {
|
||||
const deps = super.getLayerDependencies(argsRaw);
|
||||
const deps = super.getLayerDependencies(argsRaw)
|
||||
const layerSnap = argsRaw["snap_onto_layers"] ?? ""
|
||||
if (layerSnap === "") {
|
||||
return deps
|
||||
|
@ -665,35 +781,34 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
return deps
|
||||
}
|
||||
|
||||
constructElement(state, args,
|
||||
originalFeatureTags,
|
||||
guiState,
|
||||
feature,
|
||||
onCancel: () => void): BaseUIElement {
|
||||
|
||||
|
||||
constructElement(
|
||||
state,
|
||||
args,
|
||||
originalFeatureTags,
|
||||
guiState,
|
||||
feature,
|
||||
onCancel: () => void
|
||||
): BaseUIElement {
|
||||
const geometry = feature.geometry
|
||||
|
||||
if (geometry.type === "Point") {
|
||||
return new Lazy(() => ImportPointButton.createConfirmPanelForPoint(
|
||||
args,
|
||||
state,
|
||||
guiState,
|
||||
originalFeatureTags,
|
||||
feature,
|
||||
onCancel,
|
||||
() => {
|
||||
// Close the current popup
|
||||
state.selectedElement.setData(undefined)
|
||||
}
|
||||
))
|
||||
return new Lazy(() =>
|
||||
ImportPointButton.createConfirmPanelForPoint(
|
||||
args,
|
||||
state,
|
||||
guiState,
|
||||
originalFeatureTags,
|
||||
feature,
|
||||
onCancel,
|
||||
() => {
|
||||
// Close the current popup
|
||||
state.selectedElement.setData(undefined)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
console.error("Invalid type to import", geometry.type)
|
||||
return new FixedUiElement("Invalid geometry type:" + geometry.type).SetClass("alert")
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue