Fix dynamism in questions with new VariableInputElement

This commit is contained in:
pietervdvn 2021-10-03 21:44:43 +02:00
parent b6b20ed3ca
commit abae813606
6 changed files with 98 additions and 61 deletions

View file

@ -7,7 +7,6 @@ export class VariableUiElement extends BaseUIElement {
constructor(contents: UIEventSource<string | BaseUIElement | BaseUIElement[]>) { constructor(contents: UIEventSource<string | BaseUIElement | BaseUIElement[]>) {
super(); super();
this._contents = contents; this._contents = contents;
} }
protected InnerConstructElement(): HTMLElement { protected InnerConstructElement(): HTMLElement {

View file

@ -0,0 +1,35 @@
import {InputElement} from "./InputElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import BaseUIElement from "../BaseUIElement";
import {VariableUiElement} from "../Base/VariableUIElement";
export default class VariableInputElement<T> extends InputElement<T> {
private readonly value: UIEventSource<T>;
private readonly element: BaseUIElement
public readonly IsSelected: UIEventSource<boolean>;
private readonly upstream: UIEventSource<InputElement<T>>;
constructor(upstream: UIEventSource<InputElement<T>>) {
super()
this.upstream = upstream;
this.value = upstream.bind(v => v.GetValue())
this.element = new VariableUiElement(upstream)
this.IsSelected = upstream.bind(v => v.IsSelected)
}
GetValue(): UIEventSource<T> {
return this.value;
}
protected InnerConstructElement(): HTMLElement {
return this.element.ConstructElement();
}
IsValid(t: T): boolean {
return this.upstream.data.IsValid(t);
}
}

View file

@ -25,6 +25,7 @@ export default class EditableTagRendering extends Toggle {
const renderingIsShown = tags.map(tags => const renderingIsShown = tags.map(tags =>
configuration.IsKnown(tags) && configuration.IsKnown(tags) &&
(configuration?.condition?.matchesProperties(tags) ?? true)) (configuration?.condition?.matchesProperties(tags) ?? true))
super( super(
new Lazy(() => EditableTagRendering.CreateRendering(tags, configuration, units, editMode)), new Lazy(() => EditableTagRendering.CreateRendering(tags, configuration, units, editMode)),
undefined, undefined,
@ -49,8 +50,8 @@ export default class EditableTagRendering extends Toggle {
]).SetClass("flex justify-between w-full") ]).SetClass("flex justify-between w-full")
const question = new Lazy(() => { const question = new Lazy(() =>
return new TagRenderingQuestion(tags, configuration, new TagRenderingQuestion(tags, configuration,
{ {
units: units, units: units,
cancelButton: Translations.t.general.cancel.Clone() cancelButton: Translations.t.general.cancel.Clone()
@ -61,10 +62,7 @@ export default class EditableTagRendering extends Toggle {
afterSave: () => { afterSave: () => {
editMode.setData(false) editMode.setData(false)
} }
}) }))
})
rendering = new Toggle( rendering = new Toggle(

View file

@ -7,6 +7,7 @@ import BaseUIElement from "../BaseUIElement";
import {VariableUiElement} from "../Base/VariableUIElement"; import {VariableUiElement} from "../Base/VariableUIElement";
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"; import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
import {Unit} from "../../Models/Unit"; import {Unit} from "../../Models/Unit";
import Lazy from "../Base/Lazy";
/** /**
@ -27,7 +28,8 @@ export default class QuestionBox extends VariableUiElement {
} }
const tagRenderingQuestions = tagRenderings const tagRenderingQuestions = tagRenderings
.map((tagRendering, i) => new TagRenderingQuestion(tagsSource, tagRendering, .map((tagRendering, i) =>
new Lazy(() => new TagRenderingQuestion(tagsSource, tagRendering,
{ {
units: units, units: units,
afterSave: () => { afterSave: () => {
@ -41,7 +43,7 @@ export default class QuestionBox extends VariableUiElement {
skippedQuestions.ping(); skippedQuestions.ping();
}) })
} }
)); )));
const skippedQuestionsButton = Translations.t.general.skippedQuestions.Clone() const skippedQuestionsButton = Translations.t.general.skippedQuestions.Clone()
.onClick(() => { .onClick(() => {

View file

@ -26,6 +26,7 @@ import InputElementWrapper from "../Input/InputElementWrapper";
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"; import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"; import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
import {Unit} from "../../Models/Unit"; import {Unit} from "../../Models/Unit";
import VariableInputElement from "../Input/VariableInputElement";
/** /**
* Shows the question element. * Shows the question element.
@ -45,9 +46,9 @@ export default class TagRenderingQuestion extends Combine {
) { ) {
/* const applicableMappings = const applicableMappingsSrc =
UIEventSource.ListStabilized(tags.map(tags => { UIEventSource.ListStabilized(tags.map(tags => {
const applicableMappings : {if: TagsFilter, then: any, ifnot?: TagsFilter}[] = [] const applicableMappings: { if: TagsFilter, then: any, ifnot?: TagsFilter }[] = []
for (const mapping of configuration.mappings ?? []) { for (const mapping of configuration.mappings ?? []) {
if (mapping.hideInAnswer === true) { if (mapping.hideInAnswer === true) {
continue continue
@ -56,37 +57,18 @@ export default class TagRenderingQuestion extends Combine {
applicableMappings.push(mapping) applicableMappings.push(mapping)
continue continue
} }
const condition = <TagsFilter> mapping.hideInAnswer; const condition = <TagsFilter>mapping.hideInAnswer;
const isShown = !condition.matchesProperties(tags) const isShown = !condition.matchesProperties(tags)
if(isShown){ if (isShown) {
applicableMappings.push(mapping) applicableMappings.push(mapping)
} }
} }
return applicableMappings return applicableMappings
})); }));
super( applicableMappingsSrc.addCallbackAndRun(appl => console.log("Currently applicable renderings are:", appl.map(m => m.then.txt).join(", ")))
applicableMappings.map(applicableMappings => {
return TagRenderingQuestion.GenerateFullQuestion(tags, applicableMappings, configuration, options)
})
)*/
const applicableMappings = Utils.NoNull((configuration.mappings??[]).filter(mapping => mapping.hideInAnswer !== undefined))
super([TagRenderingQuestion.GenerateFullQuestion(tags, applicableMappings, configuration, options)])
}
private static GenerateFullQuestion(tags: UIEventSource<any>,
applicableMappings: {if: TagsFilter, then: any, ifnot?: TagsFilter}[],
configuration: TagRenderingConfig,
options?: {
units?: Unit[],
afterSave?: () => void,
cancelButton?: BaseUIElement,
saveButtonConstr?: (src: UIEventSource<TagsFilter>) => BaseUIElement,
bottomText?: (src: UIEventSource<TagsFilter>) => BaseUIElement
}
) {
if (configuration === undefined) { if (configuration === undefined) {
throw "A question is needed for a question visualization" throw "A question is needed for a question visualization"
} }
@ -96,13 +78,14 @@ export default class TagRenderingQuestion extends Combine {
.SetClass("question-text"); .SetClass("question-text");
const inputElement: InputElement<TagsFilter> = TagRenderingQuestion.GenerateInputElement(configuration, applicableMappings, applicableUnit, tags) const inputElement: InputElement<TagsFilter> =
new VariableInputElement(applicableMappingsSrc.map(applicableMappings =>
TagRenderingQuestion.GenerateInputElement(configuration, applicableMappings, applicableUnit, tags)
))
// inputElement.GetValue().addCallbackAndRun(s => console.trace(configuration.question.txt, "Current selection is ", s))
if (inputElement === undefined) {
console.error("MultiAnswer failed - probably not a single option was possible", configuration)
throw "MultiAnswer failed - probably not a single option was possible"
}
inputElement.GetValue().addCallbackAndRun(s => console.trace("Current selection is ", s))
const save = () => { const save = () => {
console.log("OnSaveTriggered", inputElement) console.log("OnSaveTriggered", inputElement)
const selection = inputElement.GetValue().data; const selection = inputElement.GetValue().data;
@ -151,18 +134,18 @@ export default class TagRenderingQuestion extends Combine {
) )
).SetClass("block break-all") ).SetClass("block break-all")
} }
return new Combine([ super([
question, question,
inputElement, inputElement,
options.cancelButton, options.cancelButton,
saveButton, saveButton,
bottomTags] bottomTags])
).SetClass("question") this.SetClass("question")
} }
private static GenerateInputElement(configuration: TagRenderingConfig, private static GenerateInputElement(configuration: TagRenderingConfig,
applicableMappings: {if: TagsFilter, then: any, ifnot?: TagsFilter}[], applicableMappings: { if: TagsFilter, then: any, ifnot?: TagsFilter }[],
applicableUnit: Unit, applicableUnit: Unit,
tagsSource: UIEventSource<any>) tagsSource: UIEventSource<any>)
: InputElement<TagsFilter> { : InputElement<TagsFilter> {
@ -171,7 +154,6 @@ export default class TagRenderingQuestion extends Combine {
const ff = TagRenderingQuestion.GenerateFreeform(configuration, applicableUnit, tagsSource); const ff = TagRenderingQuestion.GenerateFreeform(configuration, applicableUnit, tagsSource);
const hasImages = applicableMappings.filter(mapping => mapping.then.ExtractImages().length > 0).length > 0 const hasImages = applicableMappings.filter(mapping => mapping.then.ExtractImages().length > 0).length > 0
let inputEls: InputElement<TagsFilter>[]; let inputEls: InputElement<TagsFilter>[];
@ -226,6 +208,9 @@ export default class TagRenderingQuestion extends Combine {
if (inputEls.length == 0) { if (inputEls.length == 0) {
if(ff === undefined){
throw "Error: could not generate a question: freeform and all mappings are undefined"
}
return ff; return ff;
} }

32
test.ts
View file

@ -1,8 +1,26 @@
import Wikidata from "./Logic/Web/Wikidata"; import FeatureInfoBox from "./UI/Popup/FeatureInfoBox";
import WikipediaBox from "./UI/WikipediaBox"; import {UIEventSource} from "./Logic/UIEventSource";
import Locale from "./UI/i18n/Locale"; import AllKnownLayers from "./Customizations/AllKnownLayers";
import LanguagePicker from "./UI/LanguagePicker"; import State from "./State";
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
new WikipediaBox("Q177").SetStyle("max-height: 25rem") State.state = new State(AllKnownLayouts.allKnownLayouts.get("charging_stations"))
.AttachTo("maindiv") State.state.changes.pendingChanges.setData([])
LanguagePicker.CreateLanguagePicker(["en","nl","fr","de"]).AttachTo("extradiv") const geojson = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [51.0, 4]
},
properties:
{
id: "node/42",
amenity: "charging_station",
}
}
State.state.allElements.addOrGetElement(geojson)
const tags = State.state.allElements.getEventSourceById("node/42")
new FeatureInfoBox(
tags,
AllKnownLayers.sharedLayers.get("charging_station")
).AttachTo("maindiv")