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 DeleteButton from "./UI/Popup/DeleteWizard";
|
||||
import Combine from "./UI/Base/Combine";
|
||||
import SplitRoadWizard from "./UI/Popup/SplitRoadWizard";
|
||||
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";
|
||||
|
||||
|
||||
function TestSlideshow() {
|
||||
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")
|
||||
State.state = new State(AllKnownLayouts.layoutsList[4]);
|
||||
new SplitRoadWizard("way/1234").AttachTo("maindiv")
|
Loading…
Reference in a new issue