| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  | import {InputElement} from "./InputElement"; | 
					
						
							|  |  |  | import {UIEventSource} from "../../Logic/UIEventSource"; | 
					
						
							|  |  |  | import {Utils} from "../../Utils"; | 
					
						
							| 
									
										
										
										
											2020-06-25 03:39:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 15:54:50 +02:00
										 |  |  | export class RadioButton<T> extends InputElement<T> { | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |     private static _nextId = 0; | 
					
						
							|  |  |  |     private readonly value: UIEventSource<T>; | 
					
						
							|  |  |  |     private _elements: InputElement<T>[]; | 
					
						
							|  |  |  |     private _selectFirstAsDefault: boolean; | 
					
						
							|  |  |  |     private _dontStyle: boolean | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constructor( | 
					
						
							|  |  |  |         elements: InputElement<T>[], | 
					
						
							|  |  |  |         options?: { | 
					
						
							|  |  |  |             selectFirstAsDefault?: boolean, | 
					
						
							|  |  |  |             dontStyle?: boolean | 
					
						
							| 
									
										
										
										
											2021-07-26 17:45:54 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |     ) { | 
					
						
							|  |  |  |         super(); | 
					
						
							|  |  |  |         options = options ?? {} | 
					
						
							|  |  |  |         this._selectFirstAsDefault = options.selectFirstAsDefault ?? true; | 
					
						
							|  |  |  |         this._elements = Utils.NoNull(elements); | 
					
						
							|  |  |  |         this.value = new UIEventSource<T>(undefined); | 
					
						
							|  |  |  |         this._dontStyle = options.dontStyle ?? false | 
					
						
							| 
									
										
										
										
											2021-07-26 17:45:54 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-20 13:28:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  |     IsValid(t: T): boolean { | 
					
						
							|  |  |  |         for (const inputElement of this._elements) { | 
					
						
							|  |  |  |             if (inputElement.IsValid(t)) { | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GetValue(): UIEventSource<T> { | 
					
						
							|  |  |  |         return this.value; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |     protected InnerConstructElement(): HTMLElement { | 
					
						
							|  |  |  |         const elements = this._elements; | 
					
						
							|  |  |  |         const selectFirstAsDefault = this._selectFirstAsDefault; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const selectedElementIndex: UIEventSource<number> = | 
					
						
							|  |  |  |             new UIEventSource<number>(null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2020-07-20 13:28:45 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-14 02:39:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |         for (let i = 0; i < elements.length; i++) { | 
					
						
							|  |  |  |             // If an element is clicked, the radio button corresponding with it should be selected as well
 | 
					
						
							|  |  |  |             elements[i]?.onClick(() => { | 
					
						
							|  |  |  |                 selectedElementIndex.setData(i); | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |             elements[i].GetValue().addCallback(() => { | 
					
						
							|  |  |  |                 selectedElementIndex.setData(i); | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2021-06-14 02:39:23 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-20 13:28:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |         const groupId = "radiogroup" + RadioButton._nextId; | 
					
						
							|  |  |  |         RadioButton._nextId++; | 
					
						
							| 
									
										
										
										
											2020-07-20 15:54:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |         const form = document.createElement("form"); | 
					
						
							| 
									
										
										
										
											2020-06-25 03:39:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |         const inputs = []; | 
					
						
							|  |  |  |         const wrappers: HTMLElement[] = []; | 
					
						
							| 
									
										
										
										
											2020-07-05 18:59:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |         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( | 
					
						
							|  |  |  |                 "cursor-pointer", | 
					
						
							|  |  |  |                 "p-1", | 
					
						
							|  |  |  |                 "mr-2" | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!this._dontStyle) { | 
					
						
							|  |  |  |                 input.classList.add( | 
					
						
							|  |  |  |                     "p-1", | 
					
						
							|  |  |  |                     "ml-2", | 
					
						
							|  |  |  |                     "pl-2", | 
					
						
							|  |  |  |                     "pr-0", | 
					
						
							|  |  |  |                     "m-3", | 
					
						
							|  |  |  |                     "mr-0" | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             input.onchange = () => { | 
					
						
							|  |  |  |                 if (input.checked) { | 
					
						
							|  |  |  |                     selectedElementIndex.setData(i1); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }; | 
					
						
							| 
									
										
										
										
											2020-06-25 03:39:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |             inputs.push(input); | 
					
						
							| 
									
										
										
										
											2021-07-26 17:45:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |             const label = document.createElement("label"); | 
					
						
							|  |  |  |             label.appendChild(labelHtml); | 
					
						
							|  |  |  |             label.htmlFor = input.id; | 
					
						
							| 
									
										
										
										
											2021-07-27 19:39:57 +02:00
										 |  |  |             label.classList.add("flex", "w-full", "cursor-pointer", "bg-red"); | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (!this._dontStyle) { | 
					
						
							|  |  |  |                 labelHtml.classList.add("p-2") | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const block = document.createElement("div"); | 
					
						
							|  |  |  |             block.appendChild(input); | 
					
						
							|  |  |  |             block.appendChild(label); | 
					
						
							|  |  |  |             block.classList.add( | 
					
						
							|  |  |  |                 "flex", | 
					
						
							|  |  |  |                 "w-full", | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |             if (!this._dontStyle) { | 
					
						
							|  |  |  |                 block.classList.add( | 
					
						
							|  |  |  |                     "m-1", | 
					
						
							|  |  |  |                     "border", | 
					
						
							| 
									
										
										
										
											2022-02-01 19:02:46 +01:00
										 |  |  |                     "border-gray-400" | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |                 ) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-02-01 19:02:46 +01:00
										 |  |  |             block.style.borderRadius = "1.5rem" | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |             wrappers.push(block); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             form.appendChild(block); | 
					
						
							| 
									
										
										
										
											2020-07-20 15:54:50 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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"); | 
					
						
							| 
									
										
										
										
											2022-02-01 19:02:46 +01:00
										 |  |  |                     wrappers[i].classList.add("border-attention"); | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |                 } else { | 
					
						
							|  |  |  |                     wrappers[i].classList.add("border-gray-400"); | 
					
						
							| 
									
										
										
										
											2022-02-01 19:02:46 +01:00
										 |  |  |                     wrappers[i].classList.remove("border-attention"); | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-07-20 15:54:50 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.SetClass("flex flex-col"); | 
					
						
							| 
									
										
										
										
											2020-07-20 15:54:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:00:05 +02:00
										 |  |  |         return form; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 17:45:54 +02:00
										 |  |  | } |