Browse Source

Refactor `TableOfContents` class for least privilege

master
buttercat1791 10 months ago
parent
commit
feab392a44
  1. 9
      src/lib/components/publications/TableOfContents.svelte
  2. 51
      src/lib/components/publications/table_of_contents.svelte.ts

9
src/lib/components/publications/TableOfContents.svelte

@ -1,15 +1,10 @@ @@ -1,15 +1,10 @@
<script lang='ts'>
import { page } from '$app/state';
import type { PublicationTree } from '$lib/data_structures/publication_tree';
import type { TocEntry } from '$lib/components/publications/table_of_contents.svelte';
import type { TableOfContents } from '$lib/components/publications/table_of_contents.svelte';
import { getContext } from 'svelte';
let { rootAddress } = $props<{ rootAddress: string }>();
let publicationTree = getContext('publicationTree') as PublicationTree;
let tocAddresses = $state<Map<string, TocEntry>>(new Map());
let tocRoot = $state<TocEntry | null>(null);
let toc = getContext('toc') as TableOfContents;
// Determine the event kind.
// If index, use the publication tree to build the table of contents.

51
src/lib/components/publications/table_of_contents.svelte.ts

@ -8,15 +8,24 @@ export interface TocEntry { @@ -8,15 +8,24 @@ export interface TocEntry {
}
export class TableOfContents {
tocRoot = $state<TocEntry | null>(null);
tocAddresses = $state<Map<string, TocEntry>>(new Map());
publicationTree: PublicationTree;
pagePathname: string;
constructor(publicationTree: PublicationTree, pagePathname: string) {
this.publicationTree = publicationTree;
this.pagePathname = pagePathname;
#tocRoot: TocEntry | null = null;
#addresses = $state<Map<string, TocEntry>>(new Map());
#publicationTree: PublicationTree;
#pagePathname: string;
constructor(rootAddress: string, publicationTree: PublicationTree, pagePathname: string) {
// TODO: Build out the root entry correctly.
this.#tocRoot = {
title: '',
href: '',
expanded: false,
children: null,
};
this.#publicationTree = publicationTree;
this.#pagePathname = pagePathname;
this.insertIntoTocFromPublicationTree(rootAddress);
}
#normalizeHashPath(title: string): string {
@ -24,15 +33,19 @@ export class TableOfContents { @@ -24,15 +33,19 @@ export class TableOfContents {
return title.toLowerCase().replace(/ /g, '-');
}
get addresses(): Map<string, TocEntry> {
return this.#addresses;
}
async insertIntoTocFromPublicationTree(address: string): Promise<void> {
const targetEvent = await this.publicationTree.getEvent(address);
const targetEvent = await this.#publicationTree.getEvent(address);
if (!targetEvent) {
console.warn(`[ToC] Event ${address} not found.`);
// TODO: Determine how to handle this case in the UI.
return;
}
const hierarchyEvents = await this.publicationTree.getHierarchy(address);
const hierarchyEvents = await this.#publicationTree.getHierarchy(address);
if (hierarchyEvents.length === 0) {
// This means we are at root.
return;
@ -41,22 +54,22 @@ export class TableOfContents { @@ -41,22 +54,22 @@ export class TableOfContents {
// Michael J 05 May 2025 - In this loop, we assume that the parent of the current event has
// already been populated into the ToC. As long as the root is set when the component is
// initialized, this code will work fine.
let currentParentTocNode: TocEntry | null = this.tocRoot;
let currentParentTocNode: TocEntry | null = this.#tocRoot;
for (let i = 0; i < hierarchyEvents.length; i++) {
const currentEvent = hierarchyEvents[i];
const currentAddress = currentEvent.tagAddress();
if (this.tocAddresses.has(currentAddress)) {
if (this.#addresses.has(currentAddress)) {
continue;
}
const currentEventChildAddresses = await this.publicationTree.getChildAddresses(currentAddress);
const currentEventChildAddresses = await this.#publicationTree.getChildAddresses(currentAddress);
for (const address of currentEventChildAddresses) {
if (address === null) {
continue;
}
const childEvent = await this.publicationTree.getEvent(address);
const childEvent = await this.#publicationTree.getEvent(address);
if (!childEvent) {
console.warn(`[ToC] Event ${address} not found.`);
continue;
@ -66,15 +79,15 @@ export class TableOfContents { @@ -66,15 +79,15 @@ export class TableOfContents {
const childTocEntry: TocEntry = {
title: childEvent.getMatchingTags('title')[0][1],
href: `${this.pagePathname}#${this.#normalizeHashPath(childEvent.getMatchingTags('title')[0][1])}`,
href: `${this.#pagePathname}#${this.#normalizeHashPath(childEvent.getMatchingTags('title')[0][1])}`,
expanded: false,
children: null,
};
currentParentTocNode!.children.push(childTocEntry);
this.tocAddresses.set(address, childTocEntry);
this.#addresses.set(address, childTocEntry);
}
currentParentTocNode = this.tocAddresses.get(currentAddress)!;
currentParentTocNode = this.#addresses.get(currentAddress)!;
}
}
@ -91,7 +104,7 @@ export class TableOfContents { @@ -91,7 +104,7 @@ export class TableOfContents {
// Only create an entry if the header has an ID and a title.
if (id && title) {
const href = `${this.pagePathname}#${id}`;
const href = `${this.#pagePathname}#${id}`;
const tocEntry: TocEntry = {
title,

Loading…
Cancel
Save