151 lines
5.2 KiB
TypeScript
151 lines
5.2 KiB
TypeScript
import { Store } from "../../Logic/UIEventSource"
|
|
import BaseUIElement from "../BaseUIElement"
|
|
import Combine from "../Base/Combine"
|
|
import { SubtleButton } from "../Base/SubtleButton"
|
|
import { FixedUiElement } from "../Base/FixedUiElement"
|
|
import Translations from "../i18n/Translations"
|
|
import { VariableUiElement } from "../Base/VariableUIElement"
|
|
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
|
|
import { Tag } from "../../Logic/Tags/Tag"
|
|
import { And } from "../../Logic/Tags/And"
|
|
import Toggle from "../Input/Toggle"
|
|
import { SpecialVisualizationState } from "../SpecialVisualization"
|
|
|
|
export interface MultiApplyParams {
|
|
featureIds: Store<string[]>
|
|
keysToApply: string[]
|
|
text: string
|
|
autoapply: boolean
|
|
overwrite: boolean
|
|
tagsSource: Store<any>
|
|
state: SpecialVisualizationState
|
|
}
|
|
|
|
class MultiApplyExecutor {
|
|
private static executorCache = new Map<string, MultiApplyExecutor>()
|
|
private readonly originalValues = new Map<string, string>()
|
|
private readonly params: MultiApplyParams
|
|
|
|
private constructor(params: MultiApplyParams) {
|
|
this.params = params
|
|
const p = params
|
|
|
|
for (const key of p.keysToApply) {
|
|
this.originalValues.set(key, p.tagsSource.data[key])
|
|
}
|
|
|
|
if (p.autoapply) {
|
|
const self = this
|
|
const relevantValues = p.tagsSource.map((tags) => {
|
|
const currentValues = p.keysToApply.map((key) => tags[key])
|
|
// By stringifying, we have a very clear ping when they changec
|
|
return JSON.stringify(currentValues)
|
|
})
|
|
relevantValues.addCallbackD((_) => {
|
|
self.applyTaggingOnOtherFeatures()
|
|
})
|
|
}
|
|
}
|
|
|
|
public static GetApplicator(id: string, params: MultiApplyParams): MultiApplyExecutor {
|
|
if (MultiApplyExecutor.executorCache.has(id)) {
|
|
return MultiApplyExecutor.executorCache.get(id)
|
|
}
|
|
const applicator = new MultiApplyExecutor(params)
|
|
MultiApplyExecutor.executorCache.set(id, applicator)
|
|
return applicator
|
|
}
|
|
|
|
public applyTaggingOnOtherFeatures() {
|
|
console.log("Multi-applying changes...")
|
|
const featuresToChange = this.params.featureIds.data
|
|
const changes = this.params.state.changes
|
|
const allElements = this.params.state.featureProperties
|
|
const keysToChange = this.params.keysToApply
|
|
const overwrite = this.params.overwrite
|
|
const selfTags = this.params.tagsSource.data
|
|
const theme = this.params.state.layout.id
|
|
for (const id of featuresToChange) {
|
|
const tagsToApply: Tag[] = []
|
|
const otherFeatureTags = allElements.getStore(id).data
|
|
for (const key of keysToChange) {
|
|
const newValue = selfTags[key]
|
|
if (newValue === undefined) {
|
|
continue
|
|
}
|
|
const otherValue = otherFeatureTags[key]
|
|
if (newValue === otherValue) {
|
|
continue // No changes to be made
|
|
}
|
|
|
|
if (overwrite) {
|
|
tagsToApply.push(new Tag(key, newValue))
|
|
continue
|
|
}
|
|
|
|
if (
|
|
otherValue === undefined ||
|
|
otherValue === "" ||
|
|
otherValue === this.originalValues.get(key)
|
|
) {
|
|
tagsToApply.push(new Tag(key, newValue))
|
|
}
|
|
}
|
|
|
|
if (tagsToApply.length == 0) {
|
|
continue
|
|
}
|
|
|
|
changes.applyAction(
|
|
new ChangeTagAction(id, new And(tagsToApply), otherFeatureTags, {
|
|
theme,
|
|
changeType: "answer",
|
|
})
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
export default class MultiApply extends Toggle {
|
|
constructor(params: MultiApplyParams) {
|
|
const p = params
|
|
const t = Translations.t.multi_apply
|
|
|
|
const featureId = p.tagsSource.data.id
|
|
|
|
if (featureId === undefined) {
|
|
throw "MultiApply needs a feature id"
|
|
}
|
|
|
|
const applicator = MultiApplyExecutor.GetApplicator(featureId, params)
|
|
|
|
const elems: (string | BaseUIElement)[] = []
|
|
if (p.autoapply) {
|
|
elems.push(new FixedUiElement(p.text).SetClass("block"))
|
|
elems.push(
|
|
new VariableUiElement(
|
|
p.featureIds.map((featureIds) =>
|
|
t.autoApply.Subs({
|
|
attr_names: p.keysToApply.join(", "),
|
|
count: "" + featureIds.length,
|
|
})
|
|
)
|
|
).SetClass("block subtle text-sm")
|
|
)
|
|
} else {
|
|
elems.push(
|
|
new SubtleButton(undefined, p.text).onClick(() =>
|
|
applicator.applyTaggingOnOtherFeatures()
|
|
)
|
|
)
|
|
}
|
|
|
|
const isShown: Store<boolean> = p.state.osmConnection.isLoggedIn.map(
|
|
(loggedIn) => {
|
|
return loggedIn && p.featureIds.data.length > 0
|
|
},
|
|
[p.featureIds]
|
|
)
|
|
super(new Combine(elems), undefined, isShown)
|
|
}
|
|
}
|