Trying to get the checkboxlogic right
This commit is contained in:
parent
c944156d87
commit
e0f2f70c2e
7 changed files with 113 additions and 97 deletions
|
@ -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,
|
||||
|
|
|
@ -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,37 +56,23 @@ 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);
|
||||
self.value.ping();
|
||||
}
|
||||
} else {
|
||||
if (index >= 0) {
|
||||
self.value.data.splice(index, 1);
|
||||
self.value.ping();
|
||||
}
|
||||
if(el.checked && index < 0){
|
||||
self.value.data.push(i);
|
||||
self.value.ping();
|
||||
}else if(index >= 0){
|
||||
self.value.data.splice(index,1);
|
||||
self.value.ping();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,22 +356,20 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
|
|||
);
|
||||
};
|
||||
|
||||
const toString =
|
||||
(tag) => {
|
||||
console.log("Decoding ", tag, "in freeform text element")
|
||||
if (tag instanceof And) {
|
||||
for (const subtag of tag.and) {
|
||||
if(subtag instanceof Tag && subtag.key === freeform.key){
|
||||
return subtag.value;
|
||||
}
|
||||
const toString = (tag) => {
|
||||
if (tag instanceof And) {
|
||||
for (const subtag of tag.and) {
|
||||
if (subtag instanceof Tag && subtag.key === freeform.key) {
|
||||
return subtag.value;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
} else if (tag instanceof Tag) {
|
||||
return tag.value
|
||||
}
|
||||
|
||||
return undefined;
|
||||
} else if (tag instanceof Tag) {
|
||||
return tag.value
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
const textField = new TextField({
|
||||
|
|
|
@ -95,8 +95,12 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
|
||||
return;
|
||||
}
|
||||
this.setData(this.lastInnerRender ?? this.InnerRender());
|
||||
element.innerHTML = this.data;
|
||||
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
26
clean.sh
Executable 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
|
Loading…
Reference in a new issue