Trying to get the checkboxlogic right

This commit is contained in:
Pieter Vander Vennet 2020-09-10 21:06:56 +02:00
parent c944156d87
commit e0f2f70c2e
7 changed files with 113 additions and 97 deletions

View file

@ -462,6 +462,7 @@ export class TagUtils {
let leftoverTag = undefined;
if (keyValues[freeformKey] !== undefined && keyValues[freeformKey].length !== 0) {
leftoverTag = new Tag(freeformKey, keyValues[freeformKey].join(";"));
console.log("Leftovers are ", leftoverTag)
if (freeformExtraTags !== undefined) {
leftoverTag = new And([
leftoverTag,

View file

@ -1,52 +1,36 @@
import {InputElement} from "./InputElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import {Utils} from "../../Utils";
import {UIElement} from "../UIElement";
/**
* Supports multi-input
*/
export class CheckBoxes<T> extends InputElement<T[]> {
export class CheckBoxes extends InputElement<number[]> {
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
private readonly _selectedElementIndex: UIEventSource<number>
= new UIEventSource<number>(null);
private readonly value: UIEventSource<T[]>;
private readonly _elements: InputElement<T>[]
private readonly value: UIEventSource<number[]>;
private readonly _elements: UIElement[]
constructor(elements: InputElement<T>[]) {
constructor(elements: UIElement[]) {
super(undefined);
this._elements = Utils.NoNull(elements);
this.dumbMode = false;
this.value = new UIEventSource<T[]>([])
this.value = new UIEventSource<number[]>([])
this.ListenTo(this.value);
this.value.addCallback(latest => console.log("Latest is ", latest))
}
IsValid(ts: T[]): boolean {
IsValid(ts: number[]): boolean {
if (ts === undefined) {
return false;
}
for (const t of ts) {
let matchFound = false;
for (const element of this._elements) {
if (element.IsValid(t)) {
element.GetValue().setData(t);
matchFound = true;
break
}
}
if (!matchFound) {
return false;
}
}
return true;
}
GetValue(): UIEventSource<T[]> {
GetValue(): UIEventSource<number[]> {
return this.value;
}
@ -72,39 +56,25 @@ export class CheckBoxes<T> extends InputElement<T[]> {
super.InnerUpdate(htmlElement);
const self = this;
for (let i = 0; i < this._elements.length; i++) {
const el = document.getElementById(this.IdFor(i));
const inputEl = this._elements[i];
for (const t of this.value.data ?? []) {
if(t === undefined){
continue;
}
let isValid = inputEl.IsValid(t);
if(this.value.data.indexOf(i) >= 0){
// @ts-ignore
el.checked = isValid;
if(isValid){
break;
}
el.checked = true;
}
el.onchange = e => {
const v = inputEl.GetValue().data;
const index = self.value.data.indexOf(v);
el.onchange = () => {
const index = self.value.data.indexOf(i);
// @ts-ignore
if (el.checked) {
if (index < 0) {
self.value.data.push(v);
if(el.checked && index < 0){
self.value.data.push(i);
self.value.ping();
}
} else {
if (index >= 0) {
self.value.data.splice(index, 1);
}else if(index >= 0){
self.value.data.splice(index,1);
self.value.ping();
}
}
}
}

View file

@ -26,8 +26,6 @@ export class FixedInputElement<T> extends InputElement<T> {
}
IsValid(t: T): boolean {
console.log("Comparing ",t, "with", this.value.data);
return this._comparator(t, this.value.data);
}

View file

@ -152,7 +152,9 @@ export class TextField<T> extends InputElement<T> {
this.ListenTo(this._placeholder._source);
this._toString = options.toString ?? ((t) => ("" + t));
this.onClick(() => {
self.IsSelected.setData(true)
});
this.mappedValue.addCallback((t) => {
if (t === undefined || t === null) {
return;
@ -202,6 +204,7 @@ export class TextField<T> extends InputElement<T> {
field.addEventListener("focusin", () => self.IsSelected.setData(true));
field.addEventListener("focusout", () => self.IsSelected.setData(false));
field.addEventListener("keyup", function (event) {
if (event.key === "Enter") {
// @ts-ignore

View file

@ -205,7 +205,7 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
InputElement<TagsFilter> {
let freeformElement = undefined;
let freeformElement: InputElement<TagsFilter> = undefined;
if (options.freeform !== undefined) {
freeformElement = this.InputForFreeForm(options.freeform);
}
@ -235,45 +235,61 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
const possibleTags = elements.map(el => el.GetValue().data);
const checkBoxes = new CheckBoxes(elements);
// In order to let this work, we are cheating a lot here
// First of all, it is very tricky to let the mapping stabilize
// The selection gets added as list and needs to be flattened into a new 'and'
// This new and causes the mapping to have a 'set value', which is unpacked to update the UI
// AFter which the UI reupdates and reapplies the value
// So, instead we opt to _always return the 'value' below which is statefully updated
// But, then we still have to figure out when to update...
// For this, we use the original inputElement
// This is very dirty code, I know
const value = new And([]);
const inputElement = new InputElementMap(checkBoxes,
(t0: And, t1: And) => {
return t0?.isEquivalent(t1) ?? t0 === t1
const inputEl = new InputElementMap<number[], TagsFilter>(checkBoxes,
(t0, t1) => {
return t0?.isEquivalent(t1) ?? false
},
(fromUI) => {
if (fromUI === undefined) {
value.and = [];
return value;
(indices) => {
if (indices.length === 0) {
return undefined;
}
const flattened = TagUtils.FlattenMultiAnswer(fromUI);
value.and = flattened.and;
return value;
let tags: TagsFilter[] = indices.map(i => elements[i].GetValue().data);
return TagUtils.FlattenMultiAnswer(tags);
},
(fromTags) => {
return TagUtils.SplitMultiAnswer(fromTags, possibleTags, this._freeform?.key, this._freeform?.extraTags);
(tags: TagsFilter) => {
const splitUpValues = TagUtils.SplitMultiAnswer(tags, possibleTags, this._freeform?.key, this._freeform?.extraTags);
const indices: number[] = []
for (let i = 0; i < splitUpValues.length; i++) {
let splitUpValue = splitUpValues[i];
for (let j = 0; j < elements.length; j++) {
let inputElement = elements[j];
if (inputElement.IsValid(splitUpValue)) {
indices.push(j);
inputElement.GetValue().setData(splitUpValue);
break;
}
}
}
return indices;
}
);
let previousSelectionCount = -1;
checkBoxes.GetValue().addCallback(selected => {
const newSelectionCount = selected.length;
if (newSelectionCount != previousSelectionCount) {
previousSelectionCount = newSelectionCount;
inputElement.GetValue().ping();
freeformElement?.IsSelected.addCallback((isSelected) => {
console.log("SELECTED FF", isSelected)
if (isSelected) {
const es = checkBoxes.GetValue();
const i = elements.length - 1
if (es.data.indexOf(i) >= 0) {
return;
}
es.data.push(i);
es.ping();
}
});
return inputElement;
freeformElement?.GetValue()?.addCallback(() => {
const es = checkBoxes.GetValue();
const i = elements.length - 1
if (es.data.indexOf(i) < 0) {
es.data.push(i);
es.ping();
}
});
return inputEl;
}
return new RadioButton(elements, false);
}
@ -340,12 +356,10 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
);
};
const toString =
(tag) => {
console.log("Decoding ", tag, "in freeform text element")
const toString = (tag) => {
if (tag instanceof And) {
for (const subtag of tag.and) {
if(subtag instanceof Tag && subtag.key === freeform.key){
if (subtag instanceof Tag && subtag.key === freeform.key) {
return subtag.value;
}
}

View file

@ -95,8 +95,12 @@ export abstract class UIElement extends UIEventSource<string> {
return;
}
this.setData(this.lastInnerRender ?? this.InnerRender());
const newRender = this.InnerRender();
if (newRender !== this.lastInnerRender) {
this.setData(this.InnerRender());
element.innerHTML = this.data;
this.lastInnerRender = newRender;
}
if (this._hideIfEmpty) {
if (element.innerHTML === "") {

26
clean.sh Executable file
View file

@ -0,0 +1,26 @@
#! /bin/bash
# clean up the mess we made
# rm *.js
# rm Logic/*.js
# rm Logic/*.js
# rm Logic/*/*.js
# rm Logic/*/*/*.js
# rm UI/*.js
# rm UI/*/*.js
# rm UI/*/*/*.js
# rm Customizations/*.js
# rm Customizations/*/*.js
# rm Customizations/*/*/*.js
rm *.webmanifest
rm assets/generated/*
for f in ./*.html; do
if [[ "$f" == "./index.html" ]] || [[ "$f" == "./land.html" ]] || [[ "$f" == "./test.html" ]] || [[ "$f" == "./preferences.html" ]] || [[ "$f" == "./customGenerator.html" ]]
then
echo "Not removing $f"
else
rm $f
fi
done