| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  | import Combine from "./Combine"; | 
					
						
							|  |  |  | import BaseUIElement from "../BaseUIElement"; | 
					
						
							|  |  |  | import {Translation} from "../i18n/Translation"; | 
					
						
							|  |  |  | import {FixedUiElement} from "./FixedUiElement"; | 
					
						
							|  |  |  | import Title from "./Title"; | 
					
						
							|  |  |  | import List from "./List"; | 
					
						
							|  |  |  | import Hash from "../../Logic/Web/Hash"; | 
					
						
							|  |  |  | import Link from "./Link"; | 
					
						
							|  |  |  | import {Utils} from "../../Utils"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default class TableOfContents extends Combine { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |     private readonly titles: Title[] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |     constructor(elements: Combine | Title[], options?: { | 
					
						
							|  |  |  |         noTopLevel: false | boolean, | 
					
						
							|  |  |  |         maxDepth?: number | 
					
						
							|  |  |  |     }) { | 
					
						
							|  |  |  |         let titles: Title[] | 
					
						
							|  |  |  |         if (elements instanceof Combine) { | 
					
						
							| 
									
										
										
										
											2022-01-25 21:55:51 +01:00
										 |  |  |             titles = TableOfContents.getTitles(elements.getElements()) ?? [] | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2022-01-25 21:55:51 +01:00
										 |  |  |             titles = elements ?? [] | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |         let els: { level: number, content: BaseUIElement }[] = [] | 
					
						
							|  |  |  |         for (const title of titles) { | 
					
						
							|  |  |  |             let content: BaseUIElement | 
					
						
							|  |  |  |             if (title.title instanceof Translation) { | 
					
						
							|  |  |  |                 content = title.title.Clone() | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |             } else if (title.title instanceof FixedUiElement) { | 
					
						
							| 
									
										
										
										
											2022-01-25 21:55:51 +01:00
										 |  |  |                 content = new FixedUiElement(title.title.content) | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |             } else if (Utils.runningFromConsole) { | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |                 content = new FixedUiElement(title.AsMarkdown()) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             } else if (title["title"] !== undefined) { | 
					
						
							| 
									
										
										
										
											2022-06-28 03:21:18 +02:00
										 |  |  |                 content = new FixedUiElement(title.title.ConstructElement().textContent) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2022-01-25 21:55:51 +01:00
										 |  |  |                 console.log("Not generating a title for ", title) | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const vis = new Link(content, "#" + title.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Hash.hash.addCallbackAndRun(h => { | 
					
						
							|  |  |  |                 if (h === title.id) { | 
					
						
							|  |  |  |                     vis.SetClass("font-bold") | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     vis.RemoveClass("font-bold") | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             els.push({level: title.level, content: vis}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |         const minLevel = Math.min(...els.map(e => e.level)) | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |         if (options?.noTopLevel) { | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |             els = els.filter(e => e.level !== minLevel) | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (options?.maxDepth) { | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |             els = els.filter(e => e.level <= (options.maxDepth + minLevel)) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         super(TableOfContents.mergeLevel(els).map(el => el.SetClass("mt-2"))); | 
					
						
							|  |  |  |         this.SetClass("flex flex-col") | 
					
						
							|  |  |  |         this.titles = titles; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |     private static getTitles(elements: BaseUIElement[]): Title[] { | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |         const titles = [] | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |         for (const uiElement of elements) { | 
					
						
							|  |  |  |             if (uiElement instanceof Combine) { | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |                 titles.push(...TableOfContents.getTitles(uiElement.getElements())) | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |             } else if (uiElement instanceof Title) { | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |                 titles.push(uiElement) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return titles | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |     private static mergeLevel(elements: { level: number, content: BaseUIElement }[]): BaseUIElement[] { | 
					
						
							|  |  |  |         const maxLevel = Math.max(...elements.map(e => e.level)) | 
					
						
							|  |  |  |         const minLevel = Math.min(...elements.map(e => e.level)) | 
					
						
							|  |  |  |         if (maxLevel === minLevel) { | 
					
						
							|  |  |  |             return elements.map(e => e.content) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const result: { level: number, content: BaseUIElement } [] = [] | 
					
						
							|  |  |  |         let running: BaseUIElement[] = [] | 
					
						
							|  |  |  |         for (const element of elements) { | 
					
						
							|  |  |  |             if (element.level === maxLevel) { | 
					
						
							|  |  |  |                 running.push(element.content) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (running.length !== undefined) { | 
					
						
							|  |  |  |                 result.push({ | 
					
						
							|  |  |  |                     content: new List(running), | 
					
						
							|  |  |  |                     level: maxLevel - 1 | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |                 running = [] | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             result.push(element) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (running.length !== undefined) { | 
					
						
							|  |  |  |             result.push({ | 
					
						
							|  |  |  |                 content: new List(running), | 
					
						
							|  |  |  |                 level: maxLevel - 1 | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return TableOfContents.mergeLevel(result) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     AsMarkdown(): string { | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |         const depthIcons = ["1.", "  -", "    +", "      *"] | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |         const lines = ["## Table of contents\n"]; | 
					
						
							|  |  |  |         const minLevel = Math.min(...this.titles.map(t => t.level)) | 
					
						
							|  |  |  |         for (const title of this.titles) { | 
					
						
							|  |  |  |             const prefix = depthIcons[title.level - minLevel] ?? "        ~" | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |             const text = title.title.AsMarkdown().replace("\n", "") | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |             const link = title.id | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  |             lines.push(prefix + " [" + text + "](#" + link + ")") | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-18 18:52:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return lines.join("\n") + "\n\n" | 
					
						
							| 
									
										
										
										
											2021-11-30 22:50:48 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } |