fix(toc): doc type not rendering the first time

This commit is contained in:
Elian Doran 2025-02-07 19:23:12 +02:00
parent a98ed6cd29
commit c087d3c331
No known key found for this signature in database

View File

@ -54,9 +54,15 @@ const TPL = `<div class="toc-widget">
<span class="toc"></span> <span class="toc"></span>
</div>`; </div>`;
interface Toc {
$toc: JQuery<HTMLElement>,
headingCount: number
}
export default class TocWidget extends RightPanelWidget { export default class TocWidget extends RightPanelWidget {
private $toc!: JQuery<HTMLElement>; private $toc!: JQuery<HTMLElement>;
private tocLabelValue?: string | null;
get widgetTitle() { get widgetTitle() {
return t("toc.table_of_contents"); return t("toc.table_of_contents");
@ -101,9 +107,9 @@ export default class TocWidget extends RightPanelWidget {
this.toggleInt(!!this.noteContext?.viewScope?.tocPreviousVisible); this.toggleInt(!!this.noteContext?.viewScope?.tocPreviousVisible);
const tocLabel = note.getLabel("toc"); this.tocLabelValue = note.getLabelValue("toc");
if (tocLabel?.value === "hide") { if (this.tocLabelValue === "hide") {
this.toggleInt(false); this.toggleInt(false);
this.triggerCommand("reEvaluateRightPaneVisibility"); this.triggerCommand("reEvaluateRightPaneVisibility");
return; return;
@ -113,36 +119,47 @@ export default class TocWidget extends RightPanelWidget {
return; return;
} }
let $toc: JQuery<HTMLElement> | null = null;
let headingCount = 0;
// Check for type text unconditionally in case alwaysShowWidget is set // Check for type text unconditionally in case alwaysShowWidget is set
if (this.note.type === "text") { if (this.note.type === "text") {
const blob = await note.getBlob(); const blob = await note.getBlob();
if (blob) { if (blob) {
({ $toc, headingCount } = await this.getToc(blob.content)); const toc = await this.getToc(blob.content);
this.#updateToc(toc);
} }
} else if (this.note.type === "doc") { return;
const $contentEl = await this.noteContext.getContentElement(); }
if (this.note.type === "doc") {
/**
* For document note types, we obtain the content directly from the DOM since it allows us to obtain processed data without
* requesting data twice. However, when immediately navigating to a new note the new document is not yet attached to the hierarchy,
* resulting in an empty TOC. The fix is to simply wait for it to pop up.
*/
setTimeout(async () => {
const $contentEl = await this.noteContext?.getContentElement();
if ($contentEl) { if ($contentEl) {
const content = $contentEl.html(); const content = $contentEl.html();
({ $toc, headingCount } = await this.getToc(content)); const toc = await this.getToc(content);
this.#updateToc(toc);
} else { } else {
console.warn("Unable to get content element for doctype"); console.warn("Unable to get content element for doctype");
} }
}, 10);
}
} }
#updateToc({ $toc, headingCount }: Toc) {
this.$toc.empty(); this.$toc.empty();
if ($toc) { if ($toc) {
this.$toc.append($toc); this.$toc.append($toc);
} }
if ((tocLabel?.value === "" || tocLabel?.value === "show") || headingCount >= (options.getInt("minTocHeadings") ?? 0)) { const tocLabelValue = this.tocLabelValue;
this.toggleInt(true);
this.noteContext.viewScope.tocPreviousVisible = true; const visible = (tocLabelValue === "" || tocLabelValue === "show") || headingCount >= (options.getInt("minTocHeadings") ?? 0);
} else { this.toggleInt(visible);
this.toggleInt(false); if (this.noteContext?.viewScope) {
this.noteContext.viewScope.tocPreviousVisible = false; this.noteContext.viewScope.tocPreviousVisible = visible;
} }
this.triggerCommand("reEvaluateRightPaneVisibility"); this.triggerCommand("reEvaluateRightPaneVisibility");
@ -202,7 +219,7 @@ export default class TocWidget extends RightPanelWidget {
* with an onclick event that will cause the document to scroll to * with an onclick event that will cause the document to scroll to
* the desired position. * the desired position.
*/ */
async getToc(html: string) { async getToc(html: string): Promise<Toc> {
// Regular expression for headings <h1>...</h1> using non-greedy // Regular expression for headings <h1>...</h1> using non-greedy
// matching and backreferences // matching and backreferences
const headingTagsRegex = /<h(\d+)[^>]*>(.*?)<\/h\1>/gi; const headingTagsRegex = /<h(\d+)[^>]*>(.*?)<\/h\1>/gi;
@ -251,7 +268,7 @@ export default class TocWidget extends RightPanelWidget {
$toc = this.pullLeft($toc); $toc = this.pullLeft($toc);
return { return {
$toc: $toc, $toc,
headingCount headingCount
}; };
} }