forked from MapComplete/MapComplete
		
	Butchering the UI framework
This commit is contained in:
		
							parent
							
								
									8d404b1ba9
								
							
						
					
					
						commit
						6415e195d1
					
				
					 90 changed files with 1012 additions and 3101 deletions
				
			
		
							
								
								
									
										154
									
								
								UI/BaseUIElement.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								UI/BaseUIElement.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,154 @@ | |||
| import {Utils} from "../Utils"; | ||||
| import {UIEventSource} from "../Logic/UIEventSource"; | ||||
| 
 | ||||
| /** | ||||
|  * A thin wrapper around a html element, which allows to generate a HTML-element. | ||||
|  *  | ||||
|  * Assumes a read-only configuration, so it has no 'ListenTo' | ||||
|  */ | ||||
| export default abstract class BaseUIElement { | ||||
| 
 | ||||
|     private clss: Set<string> = new Set<string>(); | ||||
|     private style: string; | ||||
|     private _onClick: () => void; | ||||
|     private _onHover: UIEventSource<boolean>; | ||||
| 
 | ||||
|     protected _constructedHtmlElement: HTMLElement; | ||||
|      | ||||
| 
 | ||||
|     protected abstract InnerConstructElement(): HTMLElement; | ||||
| 
 | ||||
|     public onClick(f: (() => void)) { | ||||
|         this._onClick = f; | ||||
|         this.SetClass("clickable") | ||||
|         if(this._constructedHtmlElement !== undefined){ | ||||
|             this._constructedHtmlElement.onclick = f; | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public IsHovered(): UIEventSource<boolean> { | ||||
|         if (this._onHover !== undefined) { | ||||
|             return this._onHover; | ||||
|         } | ||||
|         // Note: we just save it. 'Update' will register that an eventsource exist and install the necessary hooks
 | ||||
|         this._onHover = new UIEventSource<boolean>(false); | ||||
|         return this._onHover; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     AttachTo(divId: string) { | ||||
|         let element = document.getElementById(divId); | ||||
|         if (element === null) { | ||||
|             throw "SEVERE: could not attach UIElement to " + divId; | ||||
|         } | ||||
| 
 | ||||
|         while (element.firstChild) { | ||||
|             //The list is LIVE so it will re-index each call
 | ||||
|             element.removeChild(element.firstChild); | ||||
|         } | ||||
|         const el = this.ConstructElement(); | ||||
|         if(el !== undefined){ | ||||
|             element.appendChild(el) | ||||
|         } | ||||
| 
 | ||||
|         return this; | ||||
|     } | ||||
|     /** | ||||
|      * Adds all the relevant classes, space seperated | ||||
|      * @param clss | ||||
|      * @constructor | ||||
|      */ | ||||
|     public SetClass(clss: string) { | ||||
|         const all = clss.split(" ").map(clsName => clsName.trim()); | ||||
|         let recordedChange = false; | ||||
|         for (const c of all) { | ||||
|             if (this.clss.has(clss)) { | ||||
|                 continue; | ||||
|             } | ||||
|             this.clss.add(c); | ||||
|             recordedChange = true; | ||||
|         } | ||||
|         if (recordedChange) { | ||||
|             this._constructedHtmlElement?.classList.add(...Array.from(this.clss)); | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public RemoveClass(clss: string): BaseUIElement { | ||||
|         if (this.clss.has(clss)) { | ||||
|             this.clss.delete(clss); | ||||
|             this._constructedHtmlElement?.classList.remove(clss) | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public SetStyle(style: string): BaseUIElement { | ||||
|         this.style = style; | ||||
|         if(this._constructedHtmlElement !== undefined){ | ||||
|             this._constructedHtmlElement.style.cssText = style; | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
|     /** | ||||
|      * The same as 'Render', but creates a HTML element instead of the HTML representation | ||||
|      */ | ||||
|     public ConstructElement(): HTMLElement { | ||||
|         if (Utils.runningFromConsole) { | ||||
|             return undefined; | ||||
|         } | ||||
| 
 | ||||
|         if (this._constructedHtmlElement !== undefined) { | ||||
|             return this._constructedHtmlElement | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         const el = this.InnerConstructElement(); | ||||
| 
 | ||||
|         if(el === undefined){ | ||||
|             return undefined; | ||||
|         } | ||||
| 
 | ||||
|         this._constructedHtmlElement = el; | ||||
|         const style = this.style | ||||
|         if (style !== undefined && style !== "") { | ||||
|             el.style.cssText = style | ||||
|         } | ||||
|         if (this.clss.size > 0) { | ||||
|             try{ | ||||
|                 el.classList.add(...Array.from(this.clss)) | ||||
|             }catch(e){ | ||||
|                 console.error("Invalid class name detected in:", Array.from(this.clss).join(" "),"\nErr msg is ",e) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (this._onClick !== undefined) { | ||||
|             const self = this; | ||||
|             el.onclick = (e) => { | ||||
|                 // @ts-ignore
 | ||||
|                 if (e.consumed) { | ||||
|                     return; | ||||
|                 } | ||||
|                 self._onClick(); | ||||
|                 // @ts-ignore
 | ||||
|                 e.consumed = true; | ||||
|             } | ||||
|             el.style.pointerEvents = "all"; | ||||
|             el.style.cursor = "pointer"; | ||||
|         } | ||||
| 
 | ||||
|         if (this._onHover !== undefined) { | ||||
|             const self = this; | ||||
|             el.addEventListener('mouseover', () => self._onHover.setData(true)); | ||||
|             el.addEventListener('mouseout', () => self._onHover.setData(false)); | ||||
|         } | ||||
| 
 | ||||
|         if (this._onHover !== undefined) { | ||||
|             const self = this; | ||||
|             el.addEventListener('mouseover', () => self._onHover.setData(true)); | ||||
|             el.addEventListener('mouseout', () => self._onHover.setData(false)); | ||||
|         } | ||||
| 
 | ||||
|         return el | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue