forked from MapComplete/MapComplete
		
	styling checkbox and selection
This commit is contained in:
		
							parent
							
								
									e9160504a6
								
							
						
					
					
						commit
						263cef5750
					
				
					 5 changed files with 304 additions and 237 deletions
				
			
		|  | @ -74,7 +74,6 @@ export default class FilteringFeatureSource implements FeatureSource { | ||||||
| 
 | 
 | ||||||
|           if (FilteringFeatureSource.showLayer(layer, location)) { |           if (FilteringFeatureSource.showLayer(layer, location)) { | ||||||
|             const tagsFilter = layer.appliedFilters.data; |             const tagsFilter = layer.appliedFilters.data; | ||||||
| 
 |  | ||||||
|             if (tagsFilter) { |             if (tagsFilter) { | ||||||
|               const properties = f.feature.properties; |               const properties = f.feature.properties; | ||||||
|               if (!tagsFilter.matchesProperties(properties)) { |               if (!tagsFilter.matchesProperties(properties)) { | ||||||
|  |  | ||||||
|  | @ -1,18 +1,12 @@ | ||||||
| import { Utils } from "./../../Utils"; | import { Utils } from "./../../Utils"; | ||||||
| import { FixedInputElement } from "./../Input/FixedInputElement"; | import { FixedInputElement } from "./../Input/FixedInputElement"; | ||||||
| import { RadioButton } from "./../Input/RadioButton"; | import { RadioButton } from "./../Input/RadioButton"; | ||||||
| import { FixedUiElement } from "./../Base/FixedUiElement"; |  | ||||||
| import { LayerConfigJson } from "./../../Customizations/JSON/LayerConfigJson"; |  | ||||||
| import { UIEventSource } from "../../Logic/UIEventSource"; |  | ||||||
| import { VariableUiElement } from "../Base/VariableUIElement"; | import { VariableUiElement } from "../Base/VariableUIElement"; | ||||||
| import State from "../../State"; |  | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle"; | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine"; | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations"; | ||||||
| import LayerConfig from "../../Customizations/JSON/LayerConfig"; | import LayerConfig from "../../Customizations/JSON/LayerConfig"; | ||||||
| import BaseUIElement from "../BaseUIElement"; |  | ||||||
| import { Translation } from "../i18n/Translation"; | import { Translation } from "../i18n/Translation"; | ||||||
| import ScrollableFullScreen from "../Base/ScrollableFullScreen"; |  | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg"; | ||||||
| import FilterConfig from "../../Customizations/JSON/FilterConfig"; | import FilterConfig from "../../Customizations/JSON/FilterConfig"; | ||||||
| import CheckBoxes from "../Input/Checkboxes"; | import CheckBoxes from "../Input/Checkboxes"; | ||||||
|  | @ -20,6 +14,7 @@ import { InputElement } from "../Input/InputElement"; | ||||||
| import { TagsFilter } from "../../Logic/Tags/TagsFilter"; | import { TagsFilter } from "../../Logic/Tags/TagsFilter"; | ||||||
| import InputElementMap from "../Input/InputElementMap"; | import InputElementMap from "../Input/InputElementMap"; | ||||||
| import { And } from "../../Logic/Tags/And"; | import { And } from "../../Logic/Tags/And"; | ||||||
|  | import { UIEventSource } from "../../Logic/UIEventSource"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Shows the filter |  * Shows the filter | ||||||
|  | @ -47,7 +42,8 @@ export default class FilterView extends VariableUiElement { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const style = "display:flex;align-items:center;color:#007759"; |     const style = | ||||||
|  |       "display:flex;align-items:center;color:#007759;padding:0.5rem 0;"; | ||||||
| 
 | 
 | ||||||
|     const name: Translation = Translations.WT( |     const name: Translation = Translations.WT( | ||||||
|       filteredLayer.layerDef.name |       filteredLayer.layerDef.name | ||||||
|  | @ -61,23 +57,24 @@ export default class FilterView extends VariableUiElement { | ||||||
|       .Clone() |       .Clone() | ||||||
|       .SetStyle("font-size:large;padding-left:1.25rem"); |       .SetStyle("font-size:large;padding-left:1.25rem"); | ||||||
| 
 | 
 | ||||||
|     const layerChecked = new Combine([icon, styledNameChecked]).SetStyle(style); |     const layerChecked = new Combine([icon, styledNameChecked]) | ||||||
|  |       .SetStyle(style) | ||||||
|  |       .onClick(() => filteredLayer.isDisplayed.setData(false)); | ||||||
| 
 | 
 | ||||||
|     const layerNotChecked = new Combine([ |     const layerNotChecked = new Combine([iconUnselected, styledNameUnChecked]) | ||||||
|       iconUnselected, |       .SetStyle(style) | ||||||
|       styledNameUnChecked, |       .onClick(() => filteredLayer.isDisplayed.setData(true)); | ||||||
|     ]).SetStyle(style); |  | ||||||
| 
 | 
 | ||||||
|     let listFilterElements: InputElement<TagsFilter>[] = layer.filters.map( |     let listFilterElements: InputElement<TagsFilter>[] = layer.filters.map( | ||||||
|       FilterView.createFilter |       FilterView.createFilter | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     function update() { |     const update = () => { | ||||||
|       let listTagsFilters = Utils.NoNull( |       let listTagsFilters = Utils.NoNull( | ||||||
|         listFilterElements.map((input) => input.GetValue().data) |         listFilterElements.map((input) => input.GetValue().data) | ||||||
|       ); |       ); | ||||||
|       filteredLayer.appliedTags.setData(new And(listTagsFilters)); |       filteredLayer.appliedFilters.setData(new And(listTagsFilters)); | ||||||
|     } |     }; | ||||||
| 
 | 
 | ||||||
|     listFilterElements.forEach((inputElement) => |     listFilterElements.forEach((inputElement) => | ||||||
|       inputElement.GetValue().addCallback((_) => update()) |       inputElement.GetValue().addCallback((_) => update()) | ||||||
|  | @ -87,15 +84,20 @@ export default class FilterView extends VariableUiElement { | ||||||
|       new Combine([layerChecked, ...listFilterElements]), |       new Combine([layerChecked, ...listFilterElements]), | ||||||
|       layerNotChecked, |       layerNotChecked, | ||||||
|       filteredLayer.isDisplayed |       filteredLayer.isDisplayed | ||||||
|     ) |     ).SetStyle("margin:0.3em;"); | ||||||
|       .ToggleOnClick() |  | ||||||
|       .SetStyle("margin:0.3em;"); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static createFilter(filterConfig: FilterConfig): InputElement<TagsFilter> { |   static createFilter(filterConfig: FilterConfig): InputElement<TagsFilter> { | ||||||
|     if (filterConfig.options.length === 1) { |     if (filterConfig.options.length === 1) { | ||||||
|       let option = filterConfig.options[0]; |       let option = filterConfig.options[0]; | ||||||
|       let checkboxes = new CheckBoxes([option.question.Clone()]); |       let checkboxes = new CheckBoxes( | ||||||
|  |         [option.question.Clone()], | ||||||
|  |         new UIEventSource<number[]>([]), | ||||||
|  |         "background-color: #F1F1F1;padding:0.25rem 0.5rem;", | ||||||
|  |         "border:none;padding-left:3rem;color:#007759;display:flex;margin:0;justify-content:center;align-items:center;flex-direction:row;flex-wrap:nowrap;", | ||||||
|  |         "margin:0;padding:0;", | ||||||
|  |         "margin:0;padding:0.25rem 0 0 0.25rem;" | ||||||
|  |       ); | ||||||
| 
 | 
 | ||||||
|       return new InputElementMap( |       return new InputElementMap( | ||||||
|         checkboxes, |         checkboxes, | ||||||
|  | @ -111,7 +113,11 @@ export default class FilterView extends VariableUiElement { | ||||||
|       options.map( |       options.map( | ||||||
|         (option) => |         (option) => | ||||||
|           new FixedInputElement(option.question.Clone(), option.osmTags) |           new FixedInputElement(option.question.Clone(), option.osmTags) | ||||||
|       ) |       ), | ||||||
|  |       true, | ||||||
|  |       "background-color: #F1F1F1;padding:0.25rem 0.5rem;", | ||||||
|  |       "border:none;padding-left:3rem;color:#007759;display:flex;margin:0;justify-content:center;align-items:center;flex-direction:row;flex-wrap:nowrap;", | ||||||
|  |       "margin:0;padding:0;" | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,96 +1,110 @@ | ||||||
| import {InputElement} from "./InputElement"; | import { InputElement } from "./InputElement"; | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import { UIEventSource } from "../../Logic/UIEventSource"; | ||||||
| import {Utils} from "../../Utils"; | import { Utils } from "../../Utils"; | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Supports multi-input |  * Supports multi-input | ||||||
|  */ |  */ | ||||||
| export default class CheckBoxes extends InputElement<number[]> { | export default class CheckBoxes extends InputElement<number[]> { | ||||||
|     private static _nextId = 0; |   private static _nextId = 0; | ||||||
|     IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); |   IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); | ||||||
|     private readonly value: UIEventSource<number[]> |   private readonly value: UIEventSource<number[]>; | ||||||
|     private readonly _elements: BaseUIElement[]; |   private readonly _elements: BaseUIElement[]; | ||||||
|  |   private styleWrapperOverride = ""; | ||||||
|  |   private styleInputOverride = ""; | ||||||
|  |   private styleLabelOverride = ""; | ||||||
| 
 | 
 | ||||||
|     constructor(elements: BaseUIElement[], value = new UIEventSource<number[]>([])) { |   constructor( | ||||||
|         super(); |     elements: BaseUIElement[], | ||||||
|         this.value = value; |     value = new UIEventSource<number[]>([]), | ||||||
|         this._elements = Utils.NoNull(elements); |     styleFormOverride = "", | ||||||
|         this.SetClass("flex flex-col") |     styleWrapperOverride = "", | ||||||
|  |     styleInputOverride = "", | ||||||
|  |     styleLabelOverride = "" | ||||||
|  |   ) { | ||||||
|  |     super(); | ||||||
|  |     this.value = value; | ||||||
|  |     this._elements = Utils.NoNull(elements); | ||||||
|  |     this.SetClass("flex flex-col"); | ||||||
|  |     this.SetStyle(styleFormOverride); | ||||||
|  |     this.styleWrapperOverride = styleWrapperOverride; | ||||||
|  |     this.styleInputOverride = styleInputOverride; | ||||||
|  |     this.styleLabelOverride = styleLabelOverride; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     } |   IsValid(ts: number[]): boolean { | ||||||
|  |     return ts !== undefined; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     IsValid(ts: number[]): boolean { |   GetValue(): UIEventSource<number[]> { | ||||||
|         return ts !== undefined; |     return this.value; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     } |   protected InnerConstructElement(): HTMLElement { | ||||||
|  |     const el = document.createElement("form"); | ||||||
| 
 | 
 | ||||||
|     GetValue(): UIEventSource<number[]> { |     const value = this.value; | ||||||
|         return this.value; |     const elements = this._elements; | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     protected InnerConstructElement(): HTMLElement { |     for (let i = 0; i < elements.length; i++) { | ||||||
|         const el = document.createElement("form") |       let inputI = elements[i]; | ||||||
|  |       const input = document.createElement("input"); | ||||||
|  |       const id = CheckBoxes._nextId; | ||||||
|  |       CheckBoxes._nextId++; | ||||||
|  |       input.id = "checkbox" + id; | ||||||
| 
 | 
 | ||||||
|         const value = this.value; |       input.type = "checkbox"; | ||||||
|         const elements = this._elements; |       input.classList.add("p-1", "cursor-pointer", "m-3", "pl-3", "mr-0"); | ||||||
|  |       input.style.cssText = this.styleInputOverride; | ||||||
| 
 | 
 | ||||||
|         for (let i = 0; i < elements.length; i++) { |       const label = document.createElement("label"); | ||||||
| 
 |       label.htmlFor = input.id; | ||||||
|             let inputI = elements[i]; |       label.appendChild(inputI.ConstructElement()); | ||||||
|             const input = document.createElement("input") |       label.classList.add("block", "w-full", "p-2", "cursor-pointer", "bg-red"); | ||||||
|             const id = CheckBoxes._nextId |       label.style.cssText = this.styleLabelOverride; | ||||||
|             CheckBoxes._nextId++; |  | ||||||
|             input.id = "checkbox" + id |  | ||||||
| 
 |  | ||||||
|             input.type = "checkbox" |  | ||||||
|             input.classList.add("p-1","cursor-pointer","m-3","pl-3","mr-0") |  | ||||||
| 
 |  | ||||||
|             const label = document.createElement("label") |  | ||||||
|             label.htmlFor = input.id |  | ||||||
|             label.appendChild(inputI.ConstructElement()) |  | ||||||
|             label.classList.add("block","w-full","p-2","cursor-pointer","bg-red") |  | ||||||
| 
 |  | ||||||
|             const wrapper = document.createElement("span") |  | ||||||
|             wrapper.classList.add("flex","w-full","border", "border-gray-400","m-1") |  | ||||||
|             wrapper.appendChild(input) |  | ||||||
|             wrapper.appendChild(label) |  | ||||||
|             el.appendChild(wrapper) |  | ||||||
|              |  | ||||||
|             value.addCallbackAndRunD(selectedValues => { |  | ||||||
|                 if (selectedValues.indexOf(i) >= 0) { |  | ||||||
|                     input.checked = true; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|                 if(input.checked){ |  | ||||||
|                     wrapper.classList.remove("border-gray-400") |  | ||||||
|                     wrapper.classList.add("border-black") |  | ||||||
|                 }else{ |  | ||||||
|                     wrapper.classList.add("border-gray-400") |  | ||||||
|                     wrapper.classList.remove("border-black") |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|             }) |  | ||||||
| 
 |  | ||||||
|             input.onchange = () => { |  | ||||||
|                 // Index = index in the list of already checked items
 |  | ||||||
|                 const index = value.data.indexOf(i); |  | ||||||
|                 if (input.checked && index < 0) { |  | ||||||
|                     value.data.push(i); |  | ||||||
|                     value.ping(); |  | ||||||
|                 } else if (index >= 0) { |  | ||||||
|                     value.data.splice(index, 1); |  | ||||||
|                     value.ping(); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|  |       const wrapper = document.createElement("span"); | ||||||
|  |       wrapper.classList.add( | ||||||
|  |         "wrapper", | ||||||
|  |         "flex", | ||||||
|  |         "w-full", | ||||||
|  |         "border", | ||||||
|  |         "border-gray-400", | ||||||
|  |         "m-1" | ||||||
|  |       ); | ||||||
|  |       wrapper.style.cssText = this.styleWrapperOverride; | ||||||
|  |       wrapper.appendChild(input); | ||||||
|  |       wrapper.appendChild(label); | ||||||
|  |       el.appendChild(wrapper); | ||||||
| 
 | 
 | ||||||
|  |       value.addCallbackAndRunD((selectedValues) => { | ||||||
|  |         if (selectedValues.indexOf(i) >= 0) { | ||||||
|  |           input.checked = true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if (input.checked) { | ||||||
|  |           wrapper.classList.remove("border-gray-400"); | ||||||
|  |           wrapper.classList.add("border-black"); | ||||||
|  |         } else { | ||||||
|  |           wrapper.classList.add("border-gray-400"); | ||||||
|  |           wrapper.classList.remove("border-black"); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
| 
 | 
 | ||||||
|         return el; |       input.onchange = () => { | ||||||
|  |         // Index = index in the list of already checked items
 | ||||||
|  |         const index = value.data.indexOf(i); | ||||||
|  |         if (input.checked && index < 0) { | ||||||
|  |           value.data.push(i); | ||||||
|  |           value.ping(); | ||||||
|  |         } else if (index >= 0) { | ||||||
|  |           value.data.splice(index, 1); | ||||||
|  |           value.ping(); | ||||||
|  |         } | ||||||
|  |       }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |     return el; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | @ -1,157 +1,179 @@ | ||||||
| import {InputElement} from "./InputElement"; | import { InputElement } from "./InputElement"; | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import { UIEventSource } from "../../Logic/UIEventSource"; | ||||||
| import {Utils} from "../../Utils"; | import { Utils } from "../../Utils"; | ||||||
| 
 | 
 | ||||||
| export class RadioButton<T> extends InputElement<T> { | export class RadioButton<T> extends InputElement<T> { | ||||||
|     private static _nextId = 0; |   private static _nextId = 0; | ||||||
|     IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); |   IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); | ||||||
|     private readonly value: UIEventSource<T>; |   private readonly value: UIEventSource<T>; | ||||||
|     private _elements: InputElement<T>[]; |   private _elements: InputElement<T>[]; | ||||||
|     private _selectFirstAsDefault: boolean; |   private _selectFirstAsDefault: boolean; | ||||||
|  |   private styleFormOverride = ""; | ||||||
|  |   private styleBlockOverride = ""; | ||||||
|  |   private styleInputOverride = ""; | ||||||
|  |   private styleLabelOverride = ""; | ||||||
| 
 | 
 | ||||||
|     constructor(elements: InputElement<T>[], |   constructor( | ||||||
|                 selectFirstAsDefault = true) { |     elements: InputElement<T>[], | ||||||
|         super() |     selectFirstAsDefault = true, | ||||||
|         this._selectFirstAsDefault = selectFirstAsDefault; |     styleFormOverride = "", | ||||||
|         this._elements = Utils.NoNull(elements); |     styleBlockOverride = "", | ||||||
|         this.value = new UIEventSource<T>(undefined) |     styleInputOverride = "", | ||||||
|     } |     styleLabelOverride = "" | ||||||
|     protected InnerConstructElement(): HTMLElement { |   ) { | ||||||
|         const elements = this._elements; |     super(); | ||||||
|         const selectFirstAsDefault = this._selectFirstAsDefault; |     this._selectFirstAsDefault = selectFirstAsDefault; | ||||||
|  |     this._elements = Utils.NoNull(elements); | ||||||
|  |     this.value = new UIEventSource<T>(undefined); | ||||||
|  |     this.styleFormOverride = styleFormOverride; | ||||||
|  |     this.styleBlockOverride = styleBlockOverride; | ||||||
|  |     this.styleInputOverride = styleInputOverride; | ||||||
|  |     this.styleLabelOverride = styleLabelOverride; | ||||||
|  |   } | ||||||
|  |   protected InnerConstructElement(): HTMLElement { | ||||||
|  |     const elements = this._elements; | ||||||
|  |     const selectFirstAsDefault = this._selectFirstAsDefault; | ||||||
| 
 | 
 | ||||||
|         const selectedElementIndex: UIEventSource<number> = new UIEventSource<number>(null); |     const selectedElementIndex: UIEventSource<number> = | ||||||
|         const value = |       new UIEventSource<number>(null); | ||||||
|             UIEventSource.flatten(selectedElementIndex.map( |  | ||||||
|                 (selectedIndex) => { |  | ||||||
|                     if (selectedIndex !== undefined && selectedIndex !== null) { |  | ||||||
|                         return elements[selectedIndex].GetValue() |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             ), elements.map(e => e?.GetValue())); |  | ||||||
|         value.syncWith(this.value) |  | ||||||
|          |  | ||||||
|         if(selectFirstAsDefault){ |  | ||||||
|              |  | ||||||
|         value.addCallbackAndRun(selected =>{ |  | ||||||
|             if(selected === undefined){ |  | ||||||
|                 for (const element of elements) { |  | ||||||
|                     const v = element.GetValue().data; |  | ||||||
|                     if(v !== undefined){ |  | ||||||
|                         value.setData(v) |  | ||||||
|                         break; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                  |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
| 
 | 
 | ||||||
|  |     const value = UIEventSource.flatten( | ||||||
|  |       selectedElementIndex.map((selectedIndex) => { | ||||||
|  |         if (selectedIndex !== undefined && selectedIndex !== null) { | ||||||
|  |           return elements[selectedIndex].GetValue(); | ||||||
|         } |         } | ||||||
|  |       }), | ||||||
|  |       elements.map((e) => e?.GetValue()) | ||||||
|  |     ); | ||||||
|  |     value.syncWith(this.value); | ||||||
| 
 | 
 | ||||||
|         for (let i = 0; i < elements.length; i++) { |     if (selectFirstAsDefault) { | ||||||
|             // If an element is clicked, the radio button corresponding with it should be selected as well
 |       value.addCallbackAndRun((selected) => { | ||||||
|             elements[i]?.onClick(() => { |         if (selected === undefined) { | ||||||
|                 selectedElementIndex.setData(i); |           for (const element of elements) { | ||||||
|             }); |             const v = element.GetValue().data; | ||||||
|             elements[i].IsSelected.addCallback(isSelected => { |             if (v !== undefined) { | ||||||
|                 if (isSelected) { |               value.setData(v); | ||||||
|                     selectedElementIndex.setData(i); |               break; | ||||||
|                 } |             } | ||||||
|             }) |           } | ||||||
|             elements[i].GetValue().addCallback(() => { |  | ||||||
|                 selectedElementIndex.setData(i); |  | ||||||
|             }) |  | ||||||
|         } |         } | ||||||
| 
 |       }); | ||||||
| 
 |  | ||||||
|         const groupId = "radiogroup" + RadioButton._nextId |  | ||||||
|         RadioButton._nextId++ |  | ||||||
| 
 |  | ||||||
|         const form = document.createElement("form") |  | ||||||
|         const inputs = [] |  | ||||||
|         const wrappers: HTMLElement[] = [] |  | ||||||
|          |  | ||||||
|         for (let i1 = 0; i1 < elements.length; i1++) { |  | ||||||
|             let element = elements[i1]; |  | ||||||
|             const labelHtml = element.ConstructElement(); |  | ||||||
|             if (labelHtml === undefined) { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             const input = document.createElement("input") |  | ||||||
|             input.id = "radio" + groupId + "-" + i1; |  | ||||||
|             input.name = groupId; |  | ||||||
|             input.type = "radio" |  | ||||||
|                input.classList.add("p-1","cursor-pointer","ml-2","pl-2","pr-0","m-3","mr-0") |  | ||||||
| 
 |  | ||||||
|             input.onchange = () => { |  | ||||||
|                 if(input.checked){ |  | ||||||
|                     selectedElementIndex.setData(i1) |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             |  | ||||||
|             inputs.push(input) |  | ||||||
| 
 |  | ||||||
|             const label = document.createElement("label") |  | ||||||
|             label.appendChild(labelHtml) |  | ||||||
|             label.htmlFor = input.id; |  | ||||||
|             label.classList.add("block","w-full","p-2","cursor-pointer","bg-red") |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|             const block = document.createElement("div") |  | ||||||
|             block.appendChild(input) |  | ||||||
|             block.appendChild(label) |  | ||||||
|             block.classList.add("flex","w-full","border", "rounded-3xl", "border-gray-400","m-1") |  | ||||||
|             wrappers.push(block) |  | ||||||
| 
 |  | ||||||
|             form.appendChild(block) |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|         value.addCallbackAndRun( |  | ||||||
|             selected => { |  | ||||||
| 
 |  | ||||||
|                 let somethingChecked = false; |  | ||||||
|                 for (let i = 0; i < inputs.length; i++){ |  | ||||||
|                     let input = inputs[i]; |  | ||||||
|                     input.checked = !somethingChecked && elements[i].IsValid(selected); |  | ||||||
|                     somethingChecked = somethingChecked || input.checked |  | ||||||
| 
 |  | ||||||
|                     if(input.checked){ |  | ||||||
|                         wrappers[i].classList.remove("border-gray-400") |  | ||||||
|                         wrappers[i].classList.add("border-black") |  | ||||||
|                     }else{ |  | ||||||
|                         wrappers[i].classList.add("border-gray-400") |  | ||||||
|                         wrappers[i].classList.remove("border-black") |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|         this.SetClass("flex flex-col") |  | ||||||
|         return form; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IsValid(t: T): boolean { |     for (let i = 0; i < elements.length; i++) { | ||||||
|         for (const inputElement of this._elements) { |       // If an element is clicked, the radio button corresponding with it should be selected as well
 | ||||||
|             if (inputElement.IsValid(t)) { |       elements[i]?.onClick(() => { | ||||||
|                 return true; |         selectedElementIndex.setData(i); | ||||||
|             } |       }); | ||||||
|  |       elements[i].IsSelected.addCallback((isSelected) => { | ||||||
|  |         if (isSelected) { | ||||||
|  |           selectedElementIndex.setData(i); | ||||||
|         } |         } | ||||||
|         return false; |       }); | ||||||
|  |       elements[i].GetValue().addCallback(() => { | ||||||
|  |         selectedElementIndex.setData(i); | ||||||
|  |       }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     GetValue(): UIEventSource<T> { |     const groupId = "radiogroup" + RadioButton._nextId; | ||||||
|         return this.value; |     RadioButton._nextId++; | ||||||
|  | 
 | ||||||
|  |     const form = document.createElement("form"); | ||||||
|  |     form.style.cssText = this.styleFormOverride; | ||||||
|  | 
 | ||||||
|  |     const inputs = []; | ||||||
|  |     const wrappers: HTMLElement[] = []; | ||||||
|  | 
 | ||||||
|  |     for (let i1 = 0; i1 < elements.length; i1++) { | ||||||
|  |       let element = elements[i1]; | ||||||
|  |       const labelHtml = element.ConstructElement(); | ||||||
|  |       if (labelHtml === undefined) { | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       const input = document.createElement("input"); | ||||||
|  |       input.id = "radio" + groupId + "-" + i1; | ||||||
|  |       input.name = groupId; | ||||||
|  |       input.type = "radio"; | ||||||
|  |       input.classList.add( | ||||||
|  |         "p-1", | ||||||
|  |         "cursor-pointer", | ||||||
|  |         "ml-2", | ||||||
|  |         "pl-2", | ||||||
|  |         "pr-0", | ||||||
|  |         "m-3", | ||||||
|  |         "mr-0" | ||||||
|  |       ); | ||||||
|  |       input.style.cssText = this.styleInputOverride; | ||||||
|  | 
 | ||||||
|  |       input.onchange = () => { | ||||||
|  |         if (input.checked) { | ||||||
|  |           selectedElementIndex.setData(i1); | ||||||
|  |         } | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       inputs.push(input); | ||||||
|  | 
 | ||||||
|  |       const label = document.createElement("label"); | ||||||
|  |       label.appendChild(labelHtml); | ||||||
|  |       label.htmlFor = input.id; | ||||||
|  |       label.classList.add("block", "w-full", "p-2", "cursor-pointer", "bg-red"); | ||||||
|  |       label.style.cssText = this.styleLabelOverride; | ||||||
|  | 
 | ||||||
|  |       const block = document.createElement("div"); | ||||||
|  |       block.appendChild(input); | ||||||
|  |       block.appendChild(label); | ||||||
|  |       block.classList.add( | ||||||
|  |         "flex", | ||||||
|  |         "w-full", | ||||||
|  |         "border", | ||||||
|  |         "rounded-3xl", | ||||||
|  |         "border-gray-400", | ||||||
|  |         "m-1" | ||||||
|  |       ); | ||||||
|  |       block.style.cssText = this.styleBlockOverride; | ||||||
|  |       wrappers.push(block); | ||||||
|  | 
 | ||||||
|  |       form.appendChild(block); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     value.addCallbackAndRun((selected) => { | ||||||
|  |       let somethingChecked = false; | ||||||
|  |       for (let i = 0; i < inputs.length; i++) { | ||||||
|  |         let input = inputs[i]; | ||||||
|  |         input.checked = !somethingChecked && elements[i].IsValid(selected); | ||||||
|  |         somethingChecked = somethingChecked || input.checked; | ||||||
| 
 | 
 | ||||||
|  |         if (input.checked) { | ||||||
|  |           wrappers[i].classList.remove("border-gray-400"); | ||||||
|  |           wrappers[i].classList.add("border-black"); | ||||||
|  |         } else { | ||||||
|  |           wrappers[i].classList.add("border-gray-400"); | ||||||
|  |           wrappers[i].classList.remove("border-black"); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|     /* |     this.SetClass("flex flex-col"); | ||||||
|  | 
 | ||||||
|  |     return form; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   IsValid(t: T): boolean { | ||||||
|  |     for (const inputElement of this._elements) { | ||||||
|  |       if (inputElement.IsValid(t)) { | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   GetValue(): UIEventSource<T> { | ||||||
|  |     return this.value; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /* | ||||||
|     public ShowValue(t: T): boolean { |     public ShowValue(t: T): boolean { | ||||||
|         if (t === undefined) { |         if (t === undefined) { | ||||||
|             return false; |             return false; | ||||||
|  | @ -173,6 +195,4 @@ export class RadioButton<T> extends InputElement<T> { | ||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
|     }*/ |     }*/ | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | @ -421,6 +421,34 @@ | ||||||
|           "osmTags": "books~.*children.*" |           "osmTags": "books~.*children.*" | ||||||
|         } |         } | ||||||
|       ] |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "options": [ | ||||||
|  |         { | ||||||
|  |           "question": "Boeken voor volwassenen aanwezig?", | ||||||
|  |           "osmTags": "books~.*adults.*" | ||||||
|  |         } | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "options": [ | ||||||
|  |         { | ||||||
|  |           "question": "Binnen of buiten", | ||||||
|  |           "osmTags": { | ||||||
|  |             "and": [] | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "question": "Binnen?", | ||||||
|  |           "osmTags": "indoor=yes" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "question": "Buiten?", | ||||||
|  |           "osmTags": { | ||||||
|  |             "or": ["indoor=no", "indoor="] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       ] | ||||||
|     } |     } | ||||||
|   ] |   ] | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue