diff --git a/Logic/Tags.ts b/Logic/Tags.ts index ffcc4ca0e..8ad669a74 100644 --- a/Logic/Tags.ts +++ b/Logic/Tags.ts @@ -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, diff --git a/UI/Input/Checkboxes.ts b/UI/Input/Checkboxes.ts index e515fcabd..4944f6d49 100644 --- a/UI/Input/Checkboxes.ts +++ b/UI/Input/Checkboxes.ts @@ -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 extends InputElement { +export class CheckBoxes extends InputElement { IsSelected: UIEventSource = new UIEventSource(false); - private readonly _selectedElementIndex: UIEventSource - = new UIEventSource(null); - - private readonly value: UIEventSource; - private readonly _elements: InputElement[] + private readonly value: UIEventSource; + private readonly _elements: UIElement[] - constructor(elements: InputElement[]) { + constructor(elements: UIElement[]) { super(undefined); this._elements = Utils.NoNull(elements); this.dumbMode = false; - this.value = new UIEventSource([]) + this.value = new UIEventSource([]) 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 { + GetValue(): UIEventSource { return this.value; } @@ -72,37 +56,23 @@ export class CheckBoxes extends InputElement { 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(); } } diff --git a/UI/Input/FixedInputElement.ts b/UI/Input/FixedInputElement.ts index 0309a5c0e..81f0bdf99 100644 --- a/UI/Input/FixedInputElement.ts +++ b/UI/Input/FixedInputElement.ts @@ -26,8 +26,6 @@ export class FixedInputElement extends InputElement { } IsValid(t: T): boolean { - - console.log("Comparing ",t, "with", this.value.data); return this._comparator(t, this.value.data); } diff --git a/UI/Input/TextField.ts b/UI/Input/TextField.ts index 961bdc61a..5f392dce9 100644 --- a/UI/Input/TextField.ts +++ b/UI/Input/TextField.ts @@ -152,7 +152,9 @@ export class TextField extends InputElement { 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 extends InputElement { 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 diff --git a/UI/TagRendering.ts b/UI/TagRendering.ts index 817d9208a..c39f7d578 100644 --- a/UI/TagRendering.ts +++ b/UI/TagRendering.ts @@ -205,7 +205,7 @@ export class TagRendering extends UIElement implements TagDependantUIElement { InputElement { - let freeformElement = undefined; + let freeformElement: InputElement = 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(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({ diff --git a/UI/UIElement.ts b/UI/UIElement.ts index f1c0d12f7..13311c078 100644 --- a/UI/UIElement.ts +++ b/UI/UIElement.ts @@ -95,8 +95,12 @@ export abstract class UIElement extends UIEventSource { 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 === "") { diff --git a/clean.sh b/clean.sh new file mode 100755 index 000000000..e7d32bd7d --- /dev/null +++ b/clean.sh @@ -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