forked from MapComplete/MapComplete
		
	Refactoring: move all code files into a src directory
This commit is contained in:
		
							parent
							
								
									de99f56ca8
								
							
						
					
					
						commit
						e75d2789d2
					
				
					 389 changed files with 0 additions and 12 deletions
				
			
		
							
								
								
									
										189
									
								
								src/UI/BaseUIElement.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								src/UI/BaseUIElement.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,189 @@ | |||
| /** | ||||
|  * A thin wrapper around a html element, which allows to generate a HTML-element. | ||||
|  * | ||||
|  * Assumes a read-only configuration, so it has no 'ListenTo' | ||||
|  */ | ||||
| import { Utils } from "../Utils" | ||||
| 
 | ||||
| export default abstract class BaseUIElement { | ||||
|     protected _constructedHtmlElement: HTMLElement | ||||
|     protected isDestroyed = false | ||||
|     protected readonly clss: Set<string> = new Set<string>() | ||||
|     protected style: string | ||||
|     private _onClick: () => void | Promise<void> | ||||
| 
 | ||||
|     public onClick(f: () => void) { | ||||
|         this._onClick = f | ||||
|         this.SetClass("cursor-pointer") | ||||
|         if (this._constructedHtmlElement !== undefined) { | ||||
|             this._constructedHtmlElement.onclick = f | ||||
|         } | ||||
|         return this | ||||
|     } | ||||
| 
 | ||||
|     AttachTo(divId: string) { | ||||
|         let element = document.getElementById(divId) | ||||
|         if (element === null) { | ||||
|             if (Utils.runningFromConsole) { | ||||
|                 this.ConstructElement() | ||||
|                 return | ||||
|             } | ||||
|             throw "SEVERE: could not attach UIElement to " + divId | ||||
|         } | ||||
| 
 | ||||
|         let alreadyThere = false | ||||
|         const elementToAdd = this.ConstructElement() | ||||
|         const childs = Array.from(element.childNodes) | ||||
|         for (const child of childs) { | ||||
|             if (child === elementToAdd) { | ||||
|                 alreadyThere = true | ||||
|                 continue | ||||
|             } | ||||
|             element.removeChild(child) | ||||
|         } | ||||
| 
 | ||||
|         if (elementToAdd !== undefined && !alreadyThere) { | ||||
|             element.appendChild(elementToAdd) | ||||
|         } | ||||
| 
 | ||||
|         return this | ||||
|     } | ||||
| 
 | ||||
|     public ScrollIntoView() { | ||||
|         if (this._constructedHtmlElement === undefined) { | ||||
|             return | ||||
|         } | ||||
|         this._constructedHtmlElement?.scrollIntoView({ | ||||
|             behavior: "smooth", | ||||
|             block: "start", | ||||
|         }) | ||||
|     } | ||||
|     /** | ||||
|      * Adds all the relevant classes, space separated | ||||
|      */ | ||||
|     public SetClass(clss: string) { | ||||
|         if (clss == undefined) { | ||||
|             return this | ||||
|         } | ||||
|         const all = clss.split(" ").map((clsName) => clsName.trim()) | ||||
|         let recordedChange = false | ||||
|         for (let c of all) { | ||||
|             c = c.trim() | ||||
|             if (this.clss.has(clss)) { | ||||
|                 continue | ||||
|             } | ||||
|             if (c === undefined || c === "") { | ||||
|                 continue | ||||
|             } | ||||
|             this.clss.add(c) | ||||
|             recordedChange = true | ||||
|         } | ||||
|         if (recordedChange) { | ||||
|             this._constructedHtmlElement?.classList.add(...Array.from(this.clss)) | ||||
|         } | ||||
|         return this | ||||
|     } | ||||
| 
 | ||||
|     public RemoveClass(classes: string): BaseUIElement { | ||||
|         const all = classes.split(" ").map((clsName) => clsName.trim()) | ||||
|         for (let clss of all) { | ||||
|             if (this.clss.has(clss)) { | ||||
|                 this.clss.delete(clss) | ||||
|                 this._constructedHtmlElement?.classList.remove(clss) | ||||
|             } | ||||
|         } | ||||
|         return this | ||||
|     } | ||||
| 
 | ||||
|     public HasClass(clss: string): boolean { | ||||
|         return this.clss.has(clss) | ||||
|     } | ||||
| 
 | ||||
|     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 (typeof window === undefined) { | ||||
|             return undefined | ||||
|         } | ||||
| 
 | ||||
|         if (this._constructedHtmlElement !== undefined) { | ||||
|             return this._constructedHtmlElement | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             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 = async (e) => { | ||||
|                     // @ts-ignore
 | ||||
|                     if (e.consumed) { | ||||
|                         return | ||||
|                     } | ||||
|                     const v = self._onClick() | ||||
|                     if (typeof v === "object") { | ||||
|                         await v | ||||
|                     } | ||||
|                     // @ts-ignore
 | ||||
|                     e.consumed = true | ||||
|                 } | ||||
|                 el.classList.add("cursor-pointer") | ||||
|             } | ||||
| 
 | ||||
|             return el | ||||
|         } catch (e) { | ||||
|             const domExc = e as DOMException | ||||
|             if (domExc) { | ||||
|                 console.error( | ||||
|                     "An exception occured", | ||||
|                     domExc.code, | ||||
|                     domExc.message, | ||||
|                     domExc.name, | ||||
|                     domExc | ||||
|                 ) | ||||
|             } | ||||
|             console.error(e) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public AsMarkdown(): string { | ||||
|         throw "AsMarkdown is not implemented; implement it in the subclass" | ||||
|     } | ||||
| 
 | ||||
|     public Destroy() { | ||||
|         this.isDestroyed = true | ||||
|     } | ||||
| 
 | ||||
|     protected abstract InnerConstructElement(): HTMLElement | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue