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

View file

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

View file

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

32
test.ts
View file

@ -1,8 +1,26 @@
import Wikidata from "./Logic/Web/Wikidata";
import WikipediaBox from "./UI/WikipediaBox";
import Locale from "./UI/i18n/Locale";
import LanguagePicker from "./UI/LanguagePicker";
import FeatureInfoBox from "./UI/Popup/FeatureInfoBox";
import {UIEventSource} from "./Logic/UIEventSource";
import AllKnownLayers from "./Customizations/AllKnownLayers";
import State from "./State";
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
new WikipediaBox("Q177").SetStyle("max-height: 25rem")
.AttachTo("maindiv")
LanguagePicker.CreateLanguagePicker(["en","nl","fr","de"]).AttachTo("extradiv")
State.state = new State(AllKnownLayouts.allKnownLayouts.get("charging_stations"))
State.state.changes.pendingChanges.setData([])
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")