First working version

This commit is contained in:
Pieter Vander Vennet 2022-07-10 18:08:06 +02:00
parent f79730ac0f
commit 6f5283a2d2

View file

@ -82,11 +82,11 @@ export default class TagRenderingQuestion extends Combine {
const feedback = new UIEventSource<Translation>(undefined) const feedback = new UIEventSource<Translation>(undefined)
const inputElement: ReadonlyInputElement<TagsFilter> = const inputElement: ReadonlyInputElement<TagsFilter> =
new VariableInputElement(applicableMappingsSrc.map(applicableMappings => { new VariableInputElement(applicableMappingsSrc.map(applicableMappings => {
return TagRenderingQuestion.GenerateInputElement(state, configuration, applicableMappings, applicableUnit, tags, feedback) return TagRenderingQuestion.GenerateInputElement(state, configuration, applicableMappings, applicableUnit, tags, feedback)
} }
)) ))
const save = () => { const save = () => {
const selection = inputElement.GetValue().data; const selection = inputElement.GetValue().data;
if (selection) { if (selection) {
@ -148,13 +148,16 @@ export default class TagRenderingQuestion extends Combine {
feedback: UIEventSource<Translation> feedback: UIEventSource<Translation>
): ReadonlyInputElement<TagsFilter> { ): ReadonlyInputElement<TagsFilter> {
const hasImages = applicableMappings.findIndex(mapping => mapping.icon !== undefined) >= 0 const hasImages = applicableMappings.findIndex(mapping => mapping.icon !== undefined) >= 0
let inputEls: InputElement<TagsFilter>[]; let inputEls: InputElement<TagsFilter>[];
const ifNotsPresent = applicableMappings.some(mapping => mapping.ifnot !== undefined) const ifNotsPresent = applicableMappings.some(mapping => mapping.ifnot !== undefined)
if(applicableMappings.length > 8 && !ifNotsPresent && (configuration.freeform?.type === undefined || configuration.freeform?.type === "string")){ if (applicableMappings.length > 8 &&
(configuration.freeform?.type === undefined || configuration.freeform?.type === "string") &&
(!configuration.multiAnswer || configuration.freeform === undefined)) {
return TagRenderingQuestion.GenerateSearchableSelector(state, configuration, applicableMappings, tagsSource) return TagRenderingQuestion.GenerateSearchableSelector(state, configuration, applicableMappings, tagsSource)
} }
@ -231,60 +234,96 @@ export default class TagRenderingQuestion extends Combine {
private static GenerateSearchableSelector( private static GenerateSearchableSelector(
state: FeaturePipelineState, state: FeaturePipelineState,
configuration: TagRenderingConfig, configuration: TagRenderingConfig,
applicableMappings: { if: TagsFilter; then: TypedTranslation<object>; icon?: string; iconClass?: string, addExtraTags: Tag[], searchTerms?: Record<string, string[]> }[], tagsSource: UIEventSource<any>): InputElement<TagsFilter>{ applicableMappings: { if: TagsFilter; ifnot?: TagsFilter, then: TypedTranslation<object>; icon?: string; iconClass?: string, addExtraTags: Tag[], searchTerms?: Record<string, string[]> }[], tagsSource: UIEventSource<any>): InputElement<TagsFilter> {
const values : { show: BaseUIElement, value: TagsFilter, mainTerm: Record<string, string>, searchTerms?: Record<string, string[]> }[] = [] const values: { show: BaseUIElement, value: number, mainTerm: Record<string, string>, searchTerms?: Record<string, string[]> }[] = []
for (const mapping of applicableMappings) { for (let i = 0; i < applicableMappings.length; i++) {
const mapping = applicableMappings[i];
const tr = mapping.then.Subs(tagsSource.data) const tr = mapping.then.Subs(tagsSource.data)
const patchedMapping = <{iconClass: "small-height", then: TypedTranslation<object>}> {...mapping, iconClass: "small-height"} const patchedMapping = <{ iconClass: "small-height", then: TypedTranslation<object> }>{
const fancy = TagRenderingQuestion.GenerateMappingContent(patchedMapping, tagsSource, state).SetClass("normal-background") ...mapping,
values.push({ iconClass: `small-height`,
icon: mapping.icon ?? "./assets/svg/none.svg"
}
const fancy = TagRenderingQuestion.GenerateMappingContent(patchedMapping, tagsSource, state).SetClass("normal-background")
values.push({
show: fancy, show: fancy,
value: mapping.if, value: i,
mainTerm: tr.translations, mainTerm: tr.translations,
searchTerms: mapping.searchTerms searchTerms: mapping.searchTerms
}) })
} }
const searchValue: UIEventSource<string> = new UIEventSource<string>(undefined) const searchValue: UIEventSource<string> = new UIEventSource<string>(undefined)
const ff = configuration.freeform const ff = configuration.freeform
let onEmpty : BaseUIElement = undefined let onEmpty: BaseUIElement = undefined
if(ff !== undefined){ if (ff !== undefined) {
onEmpty = new VariableUiElement(searchValue.map(search => configuration.render.Subs({[ff.key] : search}))) onEmpty = new VariableUiElement(searchValue.map(search => configuration.render.Subs({[ff.key]: search})))
} }
const classes = "h-32 overflow-scroll" const classes = "h-64 overflow-scroll"
const presetSearch = new SearchablePillsSelector<TagsFilter>(values,{ const presetSearch = new SearchablePillsSelector<number>(values, {
selectIfSingle: true, selectIfSingle: true,
mode: configuration.multiAnswer ? "select-many" : "select-one", mode: configuration.multiAnswer ? "select-many" : "select-one",
searchValue, searchValue,
onNoMatches: onEmpty?.SetClass(classes).SetClass("flex justify-center items-center"), onNoMatches: onEmpty?.SetClass(classes).SetClass("flex justify-center items-center"),
searchAreaClass:classes searchAreaClass: classes
}) })
return new InputElementMap(presetSearch, return new InputElementMap<number[], And>(presetSearch,
(x0, x1) => false, (x0, x1) => {
arr => { if (x0 == x1) {
console.log("Arr is ", arr) return true;
if(arr[0] !== undefined){
return new And(arr)
} }
if(ff !== undefined && searchValue.data?.length > 0 && !presetSearch.someMatchFound.data){ if (x0 === undefined || x1 === undefined) {
const t = new Tag(ff.key, searchValue.data) return false;
if(ff.addExtraTags){ }
return new And([t, ...ff.addExtraTags]) if (x0.and.length !== x1.and.length) {
return false;
}
for (let i = 0; i < x0.and.length; i++) {
if (x1.and[i] != x0.and[i]) {
return false
} }
return t;
} }
return undefined; return true;
}, },
tf => { (selected) => {
if(tf["and"] !== undefined){ if (ff !== undefined && searchValue.data?.length > 0 && !presetSearch.someMatchFound.data) {
return tf["and"]; const t = new Tag(ff.key, searchValue.data)
if (ff.addExtraTags) {
return new And([t, ...ff.addExtraTags])
}
return new And([t]);
} }
return [tf];
if (selected === undefined || selected.length == 0) {
return undefined;
}
const tfs = Utils.NoNull(applicableMappings.map((mapping, i) => {
if (selected.indexOf(i) >= 0) {
return mapping.if
} else {
return mapping.ifnot
}
}))
console.log("Got tags", tfs)
return new And(tfs);
},
(tf) => {
if (tf === undefined) {
return []
}
const selected: number[] = []
for (let i = 0; i < applicableMappings.length; i++) {
const mapping = applicableMappings[i]
if (tf.and.some(t => mapping.if == t)) {
selected.push(i)
}
}
return selected;
}, },
[searchValue, presetSearch.someMatchFound] [searchValue, presetSearch.someMatchFound]
); );
} }
private static GenerateMultiAnswer( private static GenerateMultiAnswer(
@ -402,7 +441,7 @@ export default class TagRenderingQuestion extends Combine {
then: Translation, then: Translation,
addExtraTags: Tag[], addExtraTags: Tag[],
icon?: string, icon?: string,
iconClass?: "small" | "medium" | "large" | "small-height" iconClass?: "small" | "medium" | "large" | "small-height"
}, ifNot?: TagsFilter[]): InputElement<TagsFilter> { }, ifNot?: TagsFilter[]): InputElement<TagsFilter> {
let tagging: TagsFilter = mapping.if; let tagging: TagsFilter = mapping.if;
@ -423,13 +462,13 @@ export default class TagRenderingQuestion extends Combine {
private static GenerateMappingContent(mapping: { private static GenerateMappingContent(mapping: {
then: Translation, then: Translation,
icon?: string, icon?: string,
iconClass?: "small" | "medium" | "large" | "small-height" iconClass?: "small" | "medium" | "large" | "small-height" | "medium-height" | "large-height"
}, tagsSource: UIEventSource<any>, state: FeaturePipelineState): BaseUIElement { }, tagsSource: UIEventSource<any>, state: FeaturePipelineState): BaseUIElement {
const text = new SubstitutedTranslation(mapping.then, tagsSource, state) const text = new SubstitutedTranslation(mapping.then, tagsSource, state)
if (mapping.icon === undefined) { if (mapping.icon === undefined) {
return text; return text;
} }
return new Combine([new Img(mapping.icon).SetClass("mr-1 mapping-icon-"+(mapping.iconClass ?? "small")), text]).SetClass("flex") return new Combine([new Img(mapping.icon).SetClass("mr-1 mapping-icon-" + (mapping.iconClass ?? "small")), text]).SetClass("flex items-center")
} }
private static GenerateFreeform(state: FeaturePipelineState, 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>)
@ -477,7 +516,7 @@ export default class TagRenderingQuestion extends Combine {
const tagsData = tags.data; const tagsData = tags.data;
const feature = state?.allElements?.ContainingFeatures?.get(tagsData.id) const feature = state?.allElements?.ContainingFeatures?.get(tagsData.id)
const center = feature != undefined ? GeoOperations.centerpointCoordinates(feature) : [0,0] const center = feature != undefined ? GeoOperations.centerpointCoordinates(feature) : [0, 0]
const input: InputElement<string> = ValidatedTextField.ForType(configuration.freeform.type)?.ConstructInputElement({ const input: InputElement<string> = ValidatedTextField.ForType(configuration.freeform.type)?.ConstructInputElement({
country: () => tagsData._country, country: () => tagsData._country,
location: [center[1], center[0]], location: [center[1], center[0]],
@ -488,13 +527,13 @@ export default class TagRenderingQuestion extends Combine {
placeholder: configuration.freeform.placeholder, placeholder: configuration.freeform.placeholder,
feedback feedback
}); });
// Init with correct value // Init with correct value
input?.GetValue().setData(tagsData[freeform.key] ?? freeform.default); input?.GetValue().setData(tagsData[freeform.key] ?? freeform.default);
// Add a length check // Add a length check
input?.GetValue().addCallbackD((v : string | undefined) => { input?.GetValue().addCallbackD((v: string | undefined) => {
if(v?.length >= 255){ if (v?.length >= 255) {
feedback.setData(Translations.t.validation.tooLong.Subs({count: v.length})) feedback.setData(Translations.t.validation.tooLong.Subs({count: v.length}))
} }
}) })
@ -513,10 +552,10 @@ export default class TagRenderingQuestion extends Combine {
return inputTagsFilter; return inputTagsFilter;
} }
public static CreateTagExplanation(selectedValue: Store<TagsFilter>, public static CreateTagExplanation(selectedValue: Store<TagsFilter>,
tags: Store<object>, tags: Store<object>,
state?: {osmConnection?: OsmConnection}){ state?: { osmConnection?: OsmConnection }) {
return new VariableUiElement( return new VariableUiElement(
selectedValue.map( selectedValue.map(
(tagsFilter: TagsFilter) => { (tagsFilter: TagsFilter) => {