mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 04:51:31 +08:00 
			
		
		
		
	chore(client/ts): port toc
This commit is contained in:
		
							parent
							
								
									d901a0f787
								
							
						
					
					
						commit
						d0317f4bb6
					
				| @ -77,6 +77,7 @@ export type CommandMappings = { | ||||
|         searchString?: string; | ||||
|         ancestorNoteId?: string | null; | ||||
|     }; | ||||
|     closeTocCommand: CommandData; | ||||
|     showLaunchBarSubtree: CommandData; | ||||
|     showOptions: CommandData & { | ||||
|         section: string; | ||||
| @ -206,6 +207,8 @@ export type CommandMappings = { | ||||
|         zoomFactor: string; | ||||
|     } | ||||
| 
 | ||||
|     reEvaluateRightPaneVisibility: CommandData; | ||||
| 
 | ||||
|     // Geomap
 | ||||
|     deleteFromMap: { noteId: string }, | ||||
|     openGeoLocation: { noteId: string, event: JQuery.MouseDownEvent } | ||||
| @ -266,6 +269,9 @@ type EventMappings = { | ||||
|     reEvaluateHighlightsListWidgetVisibility: { | ||||
|         noteId: string | undefined; | ||||
|     }; | ||||
|     reEvaluateTocWidgetVisibility: { | ||||
|         noteId: string | undefined; | ||||
|     }; | ||||
|     showHighlightsListWidget: { | ||||
|         noteId: string; | ||||
|     }; | ||||
| @ -301,7 +307,10 @@ type EventMappings = { | ||||
|     }; | ||||
|     refreshNoteList: { | ||||
|         noteId: string; | ||||
|     } | ||||
|     }; | ||||
|     showToc: { | ||||
|         noteId: string; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| export type EventListener<T extends EventNames> = { | ||||
|  | ||||
| @ -33,6 +33,14 @@ export interface ViewScope { | ||||
|     readOnlyTemporarilyDisabled?: boolean; | ||||
|     highlightsListPreviousVisible?: boolean; | ||||
|     highlightsListTemporarilyHidden?: boolean; | ||||
|     tocTemporarilyHidden?: boolean; | ||||
|     /* | ||||
|      * The reason for adding tocPreviousVisible is to record whether the previous state of the toc is hidden or displayed, | ||||
|      * and then let it be displayed/hidden at the initial time. If there is no such value, | ||||
|      * when the right panel needs to display highlighttext but not toc, every time the note content is changed, | ||||
|      * toc will appear and then close immediately, because getToc(html) function will consume time | ||||
|      */ | ||||
|     tocPreviousVisible?: boolean; | ||||
| } | ||||
| 
 | ||||
| interface CreateLinkOptions { | ||||
|  | ||||
							
								
								
									
										1
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -239,6 +239,7 @@ declare global { | ||||
|         }, | ||||
|         getData(): string; | ||||
|         setData(data: string): void; | ||||
|         sourceElement: HTMLElement; | ||||
|     } | ||||
| 
 | ||||
|     interface MentionItem { | ||||
|  | ||||
| @ -18,8 +18,9 @@ import attributeService from "../services/attributes.js"; | ||||
| import RightPanelWidget from "./right_panel_widget.js"; | ||||
| import options from "../services/options.js"; | ||||
| import OnClickButtonWidget from "./buttons/onclick_button.js"; | ||||
| import appContext from "../components/app_context.js"; | ||||
| import appContext, { type EventData } from "../components/app_context.js"; | ||||
| import libraryLoader from "../services/library_loader.js"; | ||||
| import type FNote from "../entities/fnote.js"; | ||||
| 
 | ||||
| const TPL = `<div class="toc-widget">
 | ||||
|     <style> | ||||
| @ -54,6 +55,9 @@ const TPL = `<div class="toc-widget"> | ||||
| </div>`;
 | ||||
| 
 | ||||
| export default class TocWidget extends RightPanelWidget { | ||||
| 
 | ||||
|     private $toc!: JQuery<HTMLElement>; | ||||
| 
 | ||||
|     get widgetTitle() { | ||||
|         return t("toc.table_of_contents"); | ||||
|     } | ||||
| @ -75,7 +79,7 @@ export default class TocWidget extends RightPanelWidget { | ||||
|     } | ||||
| 
 | ||||
|     isEnabled() { | ||||
|         if (!super.isEnabled()) { | ||||
|         if (!super.isEnabled() || !this.note) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
| @ -83,7 +87,9 @@ export default class TocWidget extends RightPanelWidget { | ||||
|         const isTextNote = (this.note.type === "text"); | ||||
|         const isNoteSupported = isTextNote || isHelpNote; | ||||
| 
 | ||||
|         return isNoteSupported && !this.noteContext.viewScope.tocTemporarilyHidden && this.noteContext.viewScope.viewMode === "default"; | ||||
|         return isNoteSupported | ||||
|             && !this.noteContext?.viewScope?.tocTemporarilyHidden | ||||
|             && this.noteContext?.viewScope?.viewMode === "default"; | ||||
|     } | ||||
| 
 | ||||
|     async doRenderBody() { | ||||
| @ -91,12 +97,9 @@ export default class TocWidget extends RightPanelWidget { | ||||
|         this.$toc = this.$body.find(".toc"); | ||||
|     } | ||||
| 
 | ||||
|     async refreshWithNote(note) { | ||||
|         /*The reason for adding tocPreviousVisible is to record whether the previous state of the toc is hidden or displayed, | ||||
|          * and then let it be displayed/hidden at the initial time. If there is no such value, | ||||
|          * when the right panel needs to display highlighttext but not toc, every time the note content is changed, | ||||
|          * toc will appear and then close immediately, because getToc(html) function will consume time*/ | ||||
|         this.toggleInt(!!this.noteContext.viewScope.tocPreviousVisible); | ||||
|     async refreshWithNote(note: FNote) { | ||||
| 
 | ||||
|         this.toggleInt(!!this.noteContext?.viewScope?.tocPreviousVisible); | ||||
| 
 | ||||
|         const tocLabel = note.getLabel("toc"); | ||||
| 
 | ||||
| @ -106,12 +109,19 @@ export default class TocWidget extends RightPanelWidget { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         let $toc = "", | ||||
|             headingCount = 0; | ||||
|         if (!this.note || !this.noteContext?.viewScope) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         let $toc: JQuery<HTMLElement> | null = null; | ||||
|         let headingCount = 0; | ||||
| 
 | ||||
|         // Check for type text unconditionally in case alwaysShowWidget is set
 | ||||
|         if (this.note.type === "text") { | ||||
|             const { content } = await note.getBlob(); | ||||
|             ({ $toc, headingCount } = await this.getToc(content)); | ||||
|             const blob = await note.getBlob(); | ||||
|             if (blob) { | ||||
|                 ({ $toc, headingCount } = await this.getToc(blob.content)); | ||||
|             } | ||||
|         } else if (this.note.type === "doc") { | ||||
|             const $contentEl = await this.noteContext.getContentElement(); | ||||
|             if ($contentEl) { | ||||
| @ -122,8 +132,13 @@ export default class TocWidget extends RightPanelWidget { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         this.$toc.html($toc); | ||||
|         if (["", "show"].includes(tocLabel?.value) || headingCount >= options.getInt("minTocHeadings")) { | ||||
|         if ($toc) { | ||||
|             this.$toc.append($toc); | ||||
|         } else { | ||||
|             this.$toc.empty(); | ||||
|         } | ||||
| 
 | ||||
|         if (["", "show"].includes(tocLabel?.value ?? "") || headingCount >= (options.getInt("minTocHeadings") ?? 0)) { | ||||
|             this.toggleInt(true); | ||||
|             this.noteContext.viewScope.tocPreviousVisible = true; | ||||
|         } else { | ||||
| @ -137,10 +152,10 @@ export default class TocWidget extends RightPanelWidget { | ||||
|     /** | ||||
|      * Rendering formulas in strings using katex | ||||
|      * | ||||
|      * @param {string} html Note's html content | ||||
|      * @returns {string} The HTML content with mathematical formulas rendered by KaTeX. | ||||
|      * @param html Note's html content | ||||
|      * @returns The HTML content with mathematical formulas rendered by KaTeX. | ||||
|      */ | ||||
|     async replaceMathTextWithKatax(html) { | ||||
|     async replaceMathTextWithKatax(html: string) { | ||||
|         const mathTextRegex = /<span class="math-tex">\\\(([\s\S]*?)\\\)<\/span>/g; | ||||
|         var matches = [...html.matchAll(mathTextRegex)]; | ||||
|         let modifiedText = html; | ||||
| @ -183,12 +198,12 @@ export default class TocWidget extends RightPanelWidget { | ||||
|     /** | ||||
|      * Builds a jquery table of contents. | ||||
|      * | ||||
|      * @param {string} html Note's html content | ||||
|      * @returns {$toc: jQuery, headingCount: integer} ordered list table of headings, nested by heading level | ||||
|      * @param html Note's html content | ||||
|      * @returns ordered list table of headings, nested by heading level | ||||
|      *         with an onclick event that will cause the document to scroll to | ||||
|      *         the desired position. | ||||
|      */ | ||||
|     async getToc(html) { | ||||
|     async getToc(html: string) { | ||||
|         // Regular expression for headings <h1>...</h1> using non-greedy
 | ||||
|         // matching and backreferences
 | ||||
|         const headingTagsRegex = /<h(\d+)[^>]*>(.*?)<\/h\1>/gi; | ||||
| @ -200,12 +215,12 @@ export default class TocWidget extends RightPanelWidget { | ||||
|         // Note heading 2 is the first level Trilium makes available to the note
 | ||||
|         let curLevel = 2; | ||||
|         const $ols = [$toc]; | ||||
|         let headingCount; | ||||
|         let headingCount = 0; | ||||
|         for (let m = null, headingIndex = 0; (m = headingTagsRegex.exec(html)) !== null; headingIndex++) { | ||||
|             //
 | ||||
|             // Nest/unnest whatever necessary number of ordered lists
 | ||||
|             //
 | ||||
|             const newLevel = m[1]; | ||||
|             const newLevel = parseInt(m[1]); | ||||
|             const levelDelta = newLevel - curLevel; | ||||
|             if (levelDelta > 0) { | ||||
|                 // Open as many lists as newLevel - curLevel
 | ||||
| @ -237,7 +252,7 @@ export default class TocWidget extends RightPanelWidget { | ||||
|         $toc = this.pullLeft($toc); | ||||
| 
 | ||||
|         return { | ||||
|             $toc, | ||||
|             $toc: $toc, | ||||
|             headingCount | ||||
|         }; | ||||
|     } | ||||
| @ -245,7 +260,7 @@ export default class TocWidget extends RightPanelWidget { | ||||
|     /** | ||||
|      * Reduce indent if a larger headings are not being used: https://github.com/zadam/trilium/issues/4363
 | ||||
|      */ | ||||
|     pullLeft($toc) { | ||||
|     pullLeft($toc: JQuery<HTMLElement>) { | ||||
|         while (true) { | ||||
|             const $children = $toc.children(); | ||||
| 
 | ||||
| @ -264,7 +279,11 @@ export default class TocWidget extends RightPanelWidget { | ||||
|         return $toc; | ||||
|     } | ||||
| 
 | ||||
|     async jumpToHeading(headingIndex) { | ||||
|     async jumpToHeading(headingIndex: number) { | ||||
|         if (!this.note || !this.noteContext) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // A readonly note can change state to "readonly disabled
 | ||||
|         // temporarily" (ie "edit this note" button) without any
 | ||||
|         // intervening events, do the readonly calculation at navigation
 | ||||
| @ -286,26 +305,28 @@ export default class TocWidget extends RightPanelWidget { | ||||
|     } | ||||
| 
 | ||||
|     async closeTocCommand() { | ||||
|         this.noteContext.viewScope.tocTemporarilyHidden = true; | ||||
|         if (this.noteContext?.viewScope) { | ||||
|             this.noteContext.viewScope.tocTemporarilyHidden = true; | ||||
|         } | ||||
|         await this.refresh(); | ||||
|         this.triggerCommand("reEvaluateRightPaneVisibility"); | ||||
|         appContext.triggerEvent("reEvaluateTocWidgetVisibility", { noteId: this.noteId }); | ||||
|     } | ||||
| 
 | ||||
|     async showTocWidgetEvent({ noteId }) { | ||||
|     async showTocWidgetEvent({ noteId }: EventData<"showToc">) { | ||||
|         if (this.noteId === noteId) { | ||||
|             await this.refresh(); | ||||
|             this.triggerCommand("reEvaluateRightPaneVisibility"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async entitiesReloadedEvent({ loadResults }) { | ||||
|         if (loadResults.isNoteContentReloaded(this.noteId)) { | ||||
|     async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { | ||||
|         if (this.noteId && loadResults.isNoteContentReloaded(this.noteId)) { | ||||
|             await this.refresh(); | ||||
|         } else if ( | ||||
|             loadResults | ||||
|                 .getAttributeRows() | ||||
|                 .find((attr) => attr.type === "label" && (attr.name.toLowerCase().includes("readonly") || attr.name === "toc") && attributeService.isAffecting(attr, this.note)) | ||||
|                 .find((attr) => attr.type === "label" && ((attr.name ?? "").toLowerCase().includes("readonly") || attr.name === "toc") && attributeService.isAffecting(attr, this.note)) | ||||
|         ) { | ||||
|             await this.refresh(); | ||||
|         } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran