forked from MapComplete/MapComplete
More refactoring and fixes
This commit is contained in:
parent
1bc7d9118a
commit
9877abec17
14 changed files with 375 additions and 151 deletions
|
@ -19,15 +19,15 @@ export default class CombinedInputElement<T, J, X> extends InputElement<X> {
|
|||
this._b = b;
|
||||
this._split = split;
|
||||
this._combined = new Combine([this._a, this._b]);
|
||||
this._value = this._a.GetValue().map(
|
||||
this._value = this._a.GetValue().sync(
|
||||
t => combine(t, this._b?.GetValue()?.data),
|
||||
[this._b.GetValue()],
|
||||
)
|
||||
.addCallback(x => {
|
||||
x => {
|
||||
const [t, j] = split(x)
|
||||
this._a.GetValue()?.setData(t)
|
||||
this._b.GetValue()?.setData(j)
|
||||
})
|
||||
return t
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
GetValue(): UIEventSource<X> {
|
||||
|
|
|
@ -3,6 +3,7 @@ import BaseUIElement from "../BaseUIElement";
|
|||
|
||||
export interface ReadonlyInputElement<T> extends BaseUIElement{
|
||||
GetValue(): Store<T>;
|
||||
IsValid(t: T): boolean;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import {Utils} from "../../Utils";
|
|||
|
||||
export class RadioButton<T> extends InputElement<T> {
|
||||
private static _nextId = 0;
|
||||
|
||||
private readonly value: UIEventSource<T>;
|
||||
private _elements: InputElement<T>[];
|
||||
private _selectFirstAsDefault: boolean;
|
||||
|
|
|
@ -11,7 +11,7 @@ export default class Toggle extends VariableUiElement {
|
|||
|
||||
public readonly isEnabled: Store<boolean>;
|
||||
|
||||
constructor(showEnabled: string | BaseUIElement, showDisabled: string | BaseUIElement, isEnabled: Store<boolean> = new UIEventSource<boolean>(false)) {
|
||||
constructor(showEnabled: string | BaseUIElement, showDisabled: string | BaseUIElement, isEnabled: Store<boolean>) {
|
||||
super(
|
||||
isEnabled?.map(isEnabled => isEnabled ? showEnabled : showDisabled)
|
||||
);
|
||||
|
|
|
@ -25,6 +25,7 @@ import Title from "../Base/Title";
|
|||
import InputElementMap from "./InputElementMap";
|
||||
import Translations from "../i18n/Translations";
|
||||
import {Translation} from "../i18n/Translation";
|
||||
import BaseLayer from "../../Models/BaseLayer";
|
||||
|
||||
export class TextFieldDef {
|
||||
|
||||
|
@ -71,7 +72,7 @@ export class TextFieldDef {
|
|||
placeholder?: string | BaseUIElement,
|
||||
country?: () => string,
|
||||
location?: [number /*lat*/, number /*lon*/],
|
||||
mapBackgroundLayer?: UIEventSource<any>,
|
||||
mapBackgroundLayer?: UIEventSource</*BaseLayer*/ any>,
|
||||
unit?: Unit,
|
||||
args?: (string | number | boolean)[] // Extra arguments for the inputHelper,
|
||||
feature?: any,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {InputElement, ReadonlyInputElement} from "./InputElement";
|
||||
import {ReadonlyInputElement} from "./InputElement";
|
||||
import {Store} from "../../Logic/UIEventSource";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
|
@ -7,9 +7,9 @@ export default class VariableInputElement<T> extends BaseUIElement implements Re
|
|||
|
||||
private readonly value: Store<T>;
|
||||
private readonly element: BaseUIElement
|
||||
private readonly upstream: Store<InputElement<T>>;
|
||||
private readonly upstream: Store<ReadonlyInputElement<T>>;
|
||||
|
||||
constructor(upstream: Store<InputElement<T>>) {
|
||||
constructor(upstream: Store<ReadonlyInputElement<T>>) {
|
||||
super()
|
||||
this.upstream = upstream;
|
||||
this.value = upstream.bind(v => v.GetValue())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {Store, UIEventSource} from "../../Logic/UIEventSource";
|
||||
import {ImmutableStore, Store} from "../../Logic/UIEventSource";
|
||||
import Translations from "../i18n/Translations";
|
||||
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
|
||||
import Toggle from "../Input/Toggle";
|
||||
|
@ -29,7 +29,7 @@ export class SaveButton extends Toggle {
|
|||
super(
|
||||
save,
|
||||
pleaseLogin,
|
||||
osmConnection?.isLoggedIn ?? new UIEventSource<any>(false)
|
||||
osmConnection?.isLoggedIn ?? new ImmutableStore(false)
|
||||
)
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export default class TagRenderingQuestion extends Combine {
|
|||
|
||||
constructor(tags: UIEventSource<any>,
|
||||
configuration: TagRenderingConfig,
|
||||
state,
|
||||
state?: FeaturePipelineState,
|
||||
options?: {
|
||||
units?: Unit[],
|
||||
afterSave?: () => void,
|
||||
|
@ -50,7 +50,6 @@ export default class TagRenderingQuestion extends Combine {
|
|||
}
|
||||
) {
|
||||
|
||||
|
||||
const applicableMappingsSrc =
|
||||
Stores.ListStabilized(tags.map(tags => {
|
||||
const applicableMappings: { if: TagsFilter, icon?: string, then: TypedTranslation<object>, ifnot?: TagsFilter, addExtraTags: Tag[] }[] = []
|
||||
|
@ -82,12 +81,11 @@ export default class TagRenderingQuestion extends Combine {
|
|||
|
||||
const feedback = new UIEventSource<Translation>(undefined)
|
||||
const inputElement: ReadonlyInputElement<TagsFilter> =
|
||||
new VariableInputElement(applicableMappingsSrc.map(applicableMappings =>
|
||||
TagRenderingQuestion.GenerateInputElement(state, configuration, applicableMappings, applicableUnit, tags, feedback)
|
||||
new VariableInputElement(applicableMappingsSrc.map(applicableMappings => {
|
||||
return TagRenderingQuestion.GenerateInputElement(state, configuration, applicableMappings, applicableUnit, tags, feedback)
|
||||
}
|
||||
))
|
||||
|
||||
|
||||
|
||||
const save = () => {
|
||||
const selection = inputElement.GetValue().data;
|
||||
if (selection) {
|
||||
|
@ -132,7 +130,7 @@ export default class TagRenderingQuestion extends Combine {
|
|||
saveButton]).SetClass("flex justify-end flex-wrap-reverse")
|
||||
|
||||
]).SetClass("flex mt-2 justify-between"),
|
||||
new Toggle(Translations.t.general.testing.SetClass("alert"), undefined, state.featureSwitchIsTesting)
|
||||
new Toggle(Translations.t.general.testing.SetClass("alert"), undefined, state?.featureSwitchIsTesting)
|
||||
])
|
||||
|
||||
|
||||
|
@ -141,17 +139,16 @@ export default class TagRenderingQuestion extends Combine {
|
|||
|
||||
|
||||
private static GenerateInputElement(
|
||||
state,
|
||||
state: FeaturePipelineState,
|
||||
configuration: TagRenderingConfig,
|
||||
applicableMappings: { if: TagsFilter, then: TypedTranslation<object>, icon?: string, ifnot?: TagsFilter, addExtraTags: Tag[] }[],
|
||||
applicableUnit: Unit,
|
||||
tagsSource: UIEventSource<any>,
|
||||
feedback: UIEventSource<Translation>
|
||||
): InputElement<TagsFilter> {
|
||||
): ReadonlyInputElement<TagsFilter> {
|
||||
|
||||
// FreeForm input will be undefined if not present; will already contain a special input element if applicable
|
||||
const ff = TagRenderingQuestion.GenerateFreeform(state, configuration, applicableUnit, tagsSource, feedback);
|
||||
|
||||
|
||||
const hasImages = applicableMappings.findIndex(mapping => mapping.icon !== undefined) >= 0
|
||||
let inputEls: InputElement<TagsFilter>[];
|
||||
|
@ -370,7 +367,7 @@ export default class TagRenderingQuestion extends Combine {
|
|||
return new Combine([new Img(mapping.icon).SetClass("mapping-icon-"+(mapping.iconClass ?? "small")), text]).SetClass("flex")
|
||||
}
|
||||
|
||||
private static GenerateFreeform(state, configuration: TagRenderingConfig, applicableUnit: Unit, tags: UIEventSource<any>, feedback: UIEventSource<Translation>)
|
||||
private static GenerateFreeform(state: FeaturePipelineState, configuration: TagRenderingConfig, applicableUnit: Unit, tags: UIEventSource<any>, feedback: UIEventSource<Translation>)
|
||||
: InputElement<TagsFilter> {
|
||||
const freeform = configuration.freeform;
|
||||
if (freeform === undefined) {
|
||||
|
@ -414,12 +411,12 @@ export default class TagRenderingQuestion extends Combine {
|
|||
}
|
||||
|
||||
const tagsData = tags.data;
|
||||
const feature = state.allElements.ContainingFeatures.get(tagsData.id)
|
||||
const center = GeoOperations.centerpointCoordinates(feature)
|
||||
const feature = state?.allElements?.ContainingFeatures?.get(tagsData.id)
|
||||
const center = feature != undefined ? GeoOperations.centerpointCoordinates(feature) : [0,0]
|
||||
const input: InputElement<string> = ValidatedTextField.ForType(configuration.freeform.type).ConstructInputElement({
|
||||
country: () => tagsData._country,
|
||||
location: [center[1], center[0]],
|
||||
mapBackgroundLayer: state.backgroundLayer,
|
||||
mapBackgroundLayer: state?.backgroundLayer,
|
||||
unit: applicableUnit,
|
||||
args: configuration.freeform.helperArgs,
|
||||
feature,
|
||||
|
@ -427,10 +424,12 @@ export default class TagRenderingQuestion extends Combine {
|
|||
feedback
|
||||
});
|
||||
|
||||
// Init with correct value
|
||||
input.GetValue().setData(tagsData[freeform.key] ?? freeform.default);
|
||||
|
||||
input.GetValue().addCallbackD(v => {
|
||||
if(v.length >= 255){
|
||||
// Add a length check
|
||||
input.GetValue().addCallbackD((v : string | undefined) => {
|
||||
if(v?.length >= 255){
|
||||
feedback.setData(Translations.t.validation.tooLong.Subs({count: v.length}))
|
||||
}
|
||||
})
|
||||
|
@ -441,11 +440,9 @@ export default class TagRenderingQuestion extends Combine {
|
|||
);
|
||||
|
||||
if (freeform.inline) {
|
||||
|
||||
inputTagsFilter.SetClass("w-48-imp")
|
||||
inputTagsFilter = new InputElementWrapper(inputTagsFilter, configuration.render, freeform.key, tags, state)
|
||||
inputTagsFilter.SetClass("block")
|
||||
|
||||
}
|
||||
|
||||
return inputTagsFilter;
|
||||
|
@ -470,7 +467,8 @@ export default class TagRenderingQuestion extends Combine {
|
|||
return new FixedUiElement(tagsStr).SetClass("subtle");
|
||||
}
|
||||
return tagsFilter.asHumanString(true, true, tags.data);
|
||||
}
|
||||
},
|
||||
[state?.osmConnection?.userDetails]
|
||||
)
|
||||
).SetClass("block break-all")
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue