forked from MapComplete/MapComplete
First draft of split road
This commit is contained in:
parent
f5c7683d9d
commit
ae5325d4d1
4 changed files with 173 additions and 164 deletions
7
Svg.ts
7
Svg.ts
File diff suppressed because one or more lines are too long
163
UI/Popup/SplitRoadWizard.ts
Normal file
163
UI/Popup/SplitRoadWizard.ts
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||||
|
import Toggle from "../Input/Toggle";
|
||||||
|
import Translations from "../i18n/Translations";
|
||||||
|
import Svg from "../../Svg";
|
||||||
|
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
|
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||||
|
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||||
|
import Combine from "../Base/Combine";
|
||||||
|
import {SubtleButton} from "../Base/SubtleButton";
|
||||||
|
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||||
|
import {Translation} from "../i18n/Translation";
|
||||||
|
import {AndOrTagConfigJson} from "../../Customizations/JSON/TagConfigJson";
|
||||||
|
import BaseUIElement from "../BaseUIElement";
|
||||||
|
import SplitRoadAction from "../../Logic/Osm/SplitRoadAction";
|
||||||
|
import Minimap from "../Base/Minimap";
|
||||||
|
import State from "../../State";
|
||||||
|
|
||||||
|
export default class SplitRoadWizard extends Toggle {
|
||||||
|
/**
|
||||||
|
* A UI Element used for splitting roads
|
||||||
|
*
|
||||||
|
* @param id: The id of the road to remove
|
||||||
|
*/
|
||||||
|
constructor(id: string) {
|
||||||
|
|
||||||
|
|
||||||
|
const splitClicked = new UIEventSource<boolean>(false);
|
||||||
|
|
||||||
|
const splitButton = new SubtleButton(Svg.scissors_ui(), "Split road");
|
||||||
|
splitButton.onClick(
|
||||||
|
() => {
|
||||||
|
splitClicked.setData(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// const isShown = new UIEventSource<boolean>(id.indexOf("-") < 0)
|
||||||
|
|
||||||
|
const miniMap = new Minimap({background: State.state.backgroundLayer});
|
||||||
|
|
||||||
|
super(miniMap, splitButton, splitClicked);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static constructConfirmButton(deleteReasons: UIEventSource<TagsFilter>): BaseUIElement {
|
||||||
|
const t = Translations.t.delete;
|
||||||
|
const btn = new Combine([
|
||||||
|
Svg.delete_icon_ui().SetClass("w-6 h-6 mr-3 block"),
|
||||||
|
t.delete.Clone()
|
||||||
|
]).SetClass("flex btn bg-red-500")
|
||||||
|
|
||||||
|
|
||||||
|
const btnNonActive = new Combine([
|
||||||
|
Svg.delete_icon_ui().SetClass("w-6 h-6 mr-3 block"),
|
||||||
|
t.delete.Clone()
|
||||||
|
]).SetClass("flex btn btn-disabled bg-red-200")
|
||||||
|
|
||||||
|
return new Toggle(
|
||||||
|
btn,
|
||||||
|
btnNonActive,
|
||||||
|
deleteReasons.map(reason => reason !== undefined)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static constructExplanation(tags: UIEventSource<TagsFilter>, deleteAction: SplitRoadAction) {
|
||||||
|
const t = Translations.t.delete;
|
||||||
|
return new VariableUiElement(tags.map(
|
||||||
|
currentTags => {
|
||||||
|
const cbd = deleteAction.canBeDeleted.data;
|
||||||
|
if (currentTags === undefined) {
|
||||||
|
return t.explanations.selectReason.Clone().SetClass("subtle");
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasDeletionTag = currentTags.asChange(currentTags).some(kv => kv.k === "_delete_reason")
|
||||||
|
|
||||||
|
if (cbd.canBeDeleted && hasDeletionTag) {
|
||||||
|
return t.explanations.hardDelete.Clone()
|
||||||
|
}
|
||||||
|
return new Combine([t.explanations.softDelete.Subs({reason: cbd.reason}),
|
||||||
|
new FixedUiElement(currentTags.asHumanString(false, true, currentTags)).SetClass("subtle")
|
||||||
|
]).SetClass("flex flex-col")
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
, [deleteAction.canBeDeleted]
|
||||||
|
)).SetClass("block")
|
||||||
|
}
|
||||||
|
|
||||||
|
private static generateDeleteTagRenderingConfig(softDeletionTags: TagsFilter,
|
||||||
|
nonDeleteOptions: { if: TagsFilter; then: Translation }[],
|
||||||
|
extraDeleteReasons: { explanation: Translation; changesetMessage: string }[],
|
||||||
|
currentTags: any) {
|
||||||
|
const t = Translations.t.delete
|
||||||
|
nonDeleteOptions = nonDeleteOptions ?? []
|
||||||
|
const softDeletionTagsStr = []
|
||||||
|
if (softDeletionTags !== undefined) {
|
||||||
|
softDeletionTags.asChange(currentTags)
|
||||||
|
}
|
||||||
|
const extraOptionsStr: { if: AndOrTagConfigJson, then: any }[] = []
|
||||||
|
for (const nonDeleteOption of nonDeleteOptions) {
|
||||||
|
const newIf: string[] = nonDeleteOption.if.asChange({}).map(kv => kv.k + "=" + kv.v)
|
||||||
|
|
||||||
|
extraOptionsStr.push({
|
||||||
|
if: {and: newIf},
|
||||||
|
then: nonDeleteOption.then
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const extraDeleteReason of (extraDeleteReasons ?? [])) {
|
||||||
|
extraOptionsStr.push({
|
||||||
|
if: {and: ["_delete_reason=" + extraDeleteReason.changesetMessage]},
|
||||||
|
then: extraDeleteReason.explanation
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return new TagRenderingConfig(
|
||||||
|
{
|
||||||
|
question: t.whyDelete,
|
||||||
|
render: "Deleted because {_delete_reason}",
|
||||||
|
freeform: {
|
||||||
|
key: "_delete_reason",
|
||||||
|
addExtraTags: softDeletionTagsStr
|
||||||
|
},
|
||||||
|
mappings: [
|
||||||
|
|
||||||
|
...extraOptionsStr,
|
||||||
|
|
||||||
|
{
|
||||||
|
if: {
|
||||||
|
and: [
|
||||||
|
"_delete_reason=testing point",
|
||||||
|
...softDeletionTagsStr
|
||||||
|
]
|
||||||
|
},
|
||||||
|
then: t.reasons.test
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if: {
|
||||||
|
and: [
|
||||||
|
"_delete_reason=disused",
|
||||||
|
...softDeletionTagsStr
|
||||||
|
]
|
||||||
|
},
|
||||||
|
then: t.reasons.disused
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if: {
|
||||||
|
and: [
|
||||||
|
"_delete_reason=not found",
|
||||||
|
...softDeletionTagsStr
|
||||||
|
]
|
||||||
|
},
|
||||||
|
then: t.reasons.notFound
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
}, undefined, "Delete wizard"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
assets/svg/scissors.svg
Normal file
1
assets/svg/scissors.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 5.9 KiB |
166
test.ts
166
test.ts
|
@ -1,166 +1,6 @@
|
||||||
import {OsmObject} from "./Logic/Osm/OsmObject";
|
import SplitRoadWizard from "./UI/Popup/SplitRoadWizard";
|
||||||
import DeleteButton from "./UI/Popup/DeleteWizard";
|
|
||||||
import Combine from "./UI/Base/Combine";
|
|
||||||
import State from "./State";
|
import State from "./State";
|
||||||
import DeleteWizard from "./UI/Popup/DeleteWizard";
|
|
||||||
import {UIEventSource} from "./Logic/UIEventSource";
|
|
||||||
import {Tag} from "./Logic/Tags/Tag";
|
|
||||||
import {QueryParameters} from "./Logic/Web/QueryParameters";
|
|
||||||
import {Translation} from "./UI/i18n/Translation";
|
|
||||||
/*import ValidatedTextField from "./UI/Input/ValidatedTextField";
|
|
||||||
import Combine from "./UI/Base/Combine";
|
|
||||||
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
|
||||||
import {UIEventSource} from "./Logic/UIEventSource";
|
|
||||||
import TagRenderingConfig from "./Customizations/JSON/TagRenderingConfig";
|
|
||||||
import State from "./State";
|
|
||||||
import TagRenderingQuestion from "./UI/Popup/TagRenderingQuestion";
|
|
||||||
import {SlideShow} from "./UI/Image/SlideShow";
|
|
||||||
import {FixedUiElement} from "./UI/Base/FixedUiElement";
|
|
||||||
import Img from "./UI/Base/Img";
|
|
||||||
import {AttributedImage} from "./UI/Image/AttributedImage";
|
|
||||||
import {Imgur} from "./Logic/ImageProviders/Imgur";
|
|
||||||
import Minimap from "./UI/Base/Minimap";
|
|
||||||
import Loc from "./Models/Loc";
|
|
||||||
import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers";
|
|
||||||
import ShowDataLayer from "./UI/ShowDataLayer";
|
|
||||||
import LayoutConfig from "./Customizations/JSON/LayoutConfig";
|
|
||||||
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
||||||
|
|
||||||
|
State.state = new State(AllKnownLayouts.layoutsList[4]);
|
||||||
function TestSlideshow() {
|
new SplitRoadWizard("way/1234").AttachTo("maindiv")
|
||||||
const elems = new UIEventSource([
|
|
||||||
new FixedUiElement("A"),
|
|
||||||
new FixedUiElement("qmsldkfjqmlsdkjfmqlskdjfmqlksdf").SetClass("text-xl"),
|
|
||||||
new Img("https://i.imgur.com/8lIQ5Hv.jpg"),
|
|
||||||
new AttributedImage("https://i.imgur.com/y5XudzW.jpg", Imgur.singleton),
|
|
||||||
new Img("https://www.grunge.com/img/gallery/the-real-reason-your-cat-sleeps-so-much/intro-1601496900.webp")
|
|
||||||
])
|
|
||||||
new SlideShow(elems).AttachTo("maindiv")
|
|
||||||
}
|
|
||||||
|
|
||||||
function TestTagRendering() {
|
|
||||||
State.state = new State(undefined)
|
|
||||||
const tagsSource = new UIEventSource({
|
|
||||||
id: "node/1"
|
|
||||||
})
|
|
||||||
new TagRenderingQuestion(
|
|
||||||
tagsSource,
|
|
||||||
new TagRenderingConfig({
|
|
||||||
multiAnswer: false,
|
|
||||||
freeform: {
|
|
||||||
key: "valve"
|
|
||||||
},
|
|
||||||
question: "What valves are supported?",
|
|
||||||
render: "This pump supports {valve}",
|
|
||||||
mappings: [
|
|
||||||
{
|
|
||||||
if: "valve=dunlop",
|
|
||||||
then: "This pump supports dunlop"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
if: "valve=shrader",
|
|
||||||
then: "shrader is supported",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
}, undefined, "test"),
|
|
||||||
[]
|
|
||||||
).AttachTo("maindiv")
|
|
||||||
new VariableUiElement(tagsSource.map(tags => tags["valves"])).SetClass("alert").AttachTo("extradiv")
|
|
||||||
}
|
|
||||||
|
|
||||||
function TestAllInputMethods() {
|
|
||||||
|
|
||||||
new Combine(ValidatedTextField.tpList.map(tp => {
|
|
||||||
const tf = ValidatedTextField.InputForType(tp.name);
|
|
||||||
|
|
||||||
return new Combine([tf, new VariableUiElement(tf.GetValue()).SetClass("alert")]);
|
|
||||||
})).AttachTo("maindiv")
|
|
||||||
}
|
|
||||||
|
|
||||||
function TestMiniMap() {
|
|
||||||
|
|
||||||
const location = new UIEventSource<Loc>({
|
|
||||||
lon: 4.84771728515625,
|
|
||||||
lat: 51.17920846421931,
|
|
||||||
zoom: 14
|
|
||||||
})
|
|
||||||
const map0 = new Minimap({
|
|
||||||
location: location,
|
|
||||||
allowMoving: true,
|
|
||||||
background: new AvailableBaseLayers(location).availableEditorLayers.map(layers => layers[2])
|
|
||||||
})
|
|
||||||
map0.SetStyle("width: 500px; height: 250px; overflow: hidden; border: 2px solid red")
|
|
||||||
.AttachTo("maindiv")
|
|
||||||
|
|
||||||
const layout = AllKnownLayouts.layoutsList[1]
|
|
||||||
State.state = new State(layout)
|
|
||||||
console.log("LAYOUT is", layout.id)
|
|
||||||
|
|
||||||
const feature = {
|
|
||||||
"type": "Feature",
|
|
||||||
_matching_layer_id: "bike_repair_station",
|
|
||||||
"properties": {
|
|
||||||
id: "node/-1",
|
|
||||||
"amenity": "bicycle_repair_station"
|
|
||||||
},
|
|
||||||
"geometry": {
|
|
||||||
"type": "Point",
|
|
||||||
"coordinates": [
|
|
||||||
4.84771728515625,
|
|
||||||
51.17920846421931
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
State.state.allElements.addOrGetElement(feature)
|
|
||||||
|
|
||||||
const featureSource = new UIEventSource([{
|
|
||||||
freshness: new Date(),
|
|
||||||
feature: feature
|
|
||||||
}])
|
|
||||||
|
|
||||||
new ShowDataLayer(
|
|
||||||
featureSource,
|
|
||||||
map0.leafletMap,
|
|
||||||
new UIEventSource<LayoutConfig>(layout)
|
|
||||||
)
|
|
||||||
|
|
||||||
const map1 = new Minimap({
|
|
||||||
location: location,
|
|
||||||
allowMoving: true,
|
|
||||||
background: new AvailableBaseLayers(location).availableEditorLayers.map(layers => layers[5])
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
map1.SetStyle("width: 500px; height: 250px; overflow: hidden; border : 2px solid black")
|
|
||||||
.AttachTo("extradiv")
|
|
||||||
|
|
||||||
|
|
||||||
new ShowDataLayer(
|
|
||||||
featureSource,
|
|
||||||
map1.leafletMap,
|
|
||||||
new UIEventSource<LayoutConfig>(layout)
|
|
||||||
)
|
|
||||||
|
|
||||||
featureSource.ping()
|
|
||||||
}
|
|
||||||
//*/
|
|
||||||
QueryParameters.GetQueryParameter("test", "true").setData("true")
|
|
||||||
State.state= new State(undefined)
|
|
||||||
const id = "node/5414688303"
|
|
||||||
State.state.allElements.addElementById(id, new UIEventSource<any>({id: id}))
|
|
||||||
new Combine([
|
|
||||||
new DeleteWizard(id, {
|
|
||||||
noDeleteOptions: [
|
|
||||||
{
|
|
||||||
if:[ new Tag("access","private")],
|
|
||||||
then: new Translation({
|
|
||||||
en: "Very private! Delete now or me send lawfull lawyer"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
]).AttachTo("maindiv")
|
|
Loading…
Reference in a new issue