/** * Automated Table of Contents Generator * Scans document for headings and generates TOC with REAL page numbers from PDF */ class TOCGenerator { constructor() { this.tocContainer = null; this.headings = []; this.pageNumbers = {}; this.totalPages = 0; } /** * Initialize the TOC generator */ async init() { console.log('๐Ÿš€ TOC Generator initializing...'); // Find the TOC container this.tocContainer = document.querySelector('.toc-auto'); if (!this.tocContainer) { console.error('โŒ TOC container not found. Looking for .toc-auto class.'); return; } console.log('โœ… TOC container found:', this.tocContainer); // Load real page numbers from PDF analysis await this.loadPageNumbers(); // Generate TOC this.generateTOC(); // Add event listener for dynamic updates this.setupDynamicUpdates(); console.log('โœ… TOC Generator initialized successfully'); } /** * Load real page numbers from the JSON file generated by PDF analysis */ async loadPageNumbers() { try { // Try to load page numbers from the JSON file const response = await fetch('../page_numbers.json'); if (response.ok) { this.pageNumbers = await response.json(); console.log('โœ… Loaded real page numbers from PDF analysis'); // Calculate total pages from the highest page number this.totalPages = Math.max(...Object.values(this.pageNumbers)); console.log(`๐Ÿ“Š Total pages from PDF analysis: ${this.totalPages}`); // Update CSS variable immediately if (this.totalPages) { document.documentElement.style.setProperty('--total-pages', this.totalPages); console.log(`๐ŸŽจ CSS variable --total-pages set to: ${this.totalPages}`); } else { console.error('โŒ Cannot set CSS variable: totalPages is null'); } } else { console.error('โŒ Page numbers file not found or empty'); this.pageNumbers = {}; this.totalPages = null; // No hardcoded value! } } catch (error) { console.error('โŒ ERROR: Cannot load page numbers from JSON file!'); console.error(' This usually means:'); console.error(' 1. The HTML file is opened directly (file://) instead of through a web server'); console.error(' 2. The page_numbers.json file is missing or corrupted'); console.error(' 3. CORS policy is blocking the request'); console.error(' Solution: Run the HTML through a local web server or fix the JSON file path'); console.error(' Original error:', error); // Show error in TOC container instead of hardcoded values this.tocContainer.innerHTML = `

โŒ Fehler beim Laden der Seitennummern

Problem: Die Datei page_numbers.json kann nicht geladen werden.

Mรถgliche Ursachen:

Lรถsung: Fรผhren Sie main.py aus, um PDF zu generieren und zu analysieren.

`; this.pageNumbers = {}; this.totalPages = null; // No hardcoded value! // Still try to generate TOC with estimated numbers console.log('๐Ÿ”„ Attempting to generate TOC with estimated numbers...'); this.generateTOC(); } } /** * Generate the complete TOC */ generateTOC() { console.log('๐Ÿ”„ Generating TOC...'); // Clear existing content this.tocContainer.innerHTML = '

Inhaltsverzeichnis

'; // Find all headings with specific classes this.headings = []; // Try different selectors to find headings const headingSelectors = [ 'h1.content-heading.heading-level-1', 'h2.content-heading.heading-level-2', 'h3.content-heading.heading-level-3', 'h1.heading-level-1', 'h2.heading-level-2', 'h3.heading-level-3', 'h1.content-heading', 'h2.content-heading', 'h3.content-heading' ]; console.log('๐Ÿ” Looking for headings with selectors:', headingSelectors); let foundAny = false; headingSelectors.forEach(selector => { const elements = document.querySelectorAll(selector); console.log(`๐Ÿ“‹ Found ${elements.length} elements for selector: ${selector}`); if (elements.length > 0) { foundAny = true; } elements.forEach(element => { // Get the text content WITH the numbering const text = element.textContent.trim(); const level = element.classList.contains('heading-level-1') ? 1 : element.classList.contains('heading-level-2') ? 2 : 3; console.log(`๐Ÿ“ Heading: "${text}" (Level ${level})`); // Only add if we don't already have this text if (!this.headings.some(h => h.text === text)) { this.headings.push({ element: element, text: text, level: level, page: this.estimatePageNumber(element) }); } }); }); if (!foundAny) { console.log('โš ๏ธ No headings found with any selector. Trying generic h1, h2, h3...'); const genericHeadings = document.querySelectorAll('h1, h2, h3'); console.log(`๐Ÿ“‹ Found ${genericHeadings.length} generic headings`); genericHeadings.forEach((element, index) => { const text = element.textContent.trim(); const level = element.tagName === 'H1' ? 1 : element.tagName === 'H2' ? 2 : 3; console.log(`๐Ÿ“ Generic Heading: "${text}" (Level ${level})`); this.headings.push({ element: element, text: text, level: level, page: 3 + Math.floor(index / 2) // Simple page estimation }); }); } console.log(`๐Ÿ“Š Total headings found: ${this.headings.length}`); // Sort headings by their position in the document this.headings.sort((a, b) => { const posA = a.element.getBoundingClientRect().top; const posB = b.element.getBoundingClientRect().top; return posA - posB; }); // Generate TOC entries this.headings.forEach(heading => { const entry = this.createTOCEntry(heading); this.tocContainer.appendChild(entry); }); // Update total pages based on actual content if (this.headings.length > 0) { const maxPage = Math.max(...this.headings.map(h => h.page)); this.totalPages = maxPage; console.log(`๐Ÿ“Š Total pages calculated: ${this.totalPages}`); // Update CSS variable for footers document.documentElement.style.setProperty('--total-pages', this.totalPages); // Update footer text to show total pages this.updateFooterText(); } console.log('โœ… TOC generation complete'); } /* Removed getRealPageNumber function - using direct estimation instead */ /** * Estimate page number (fallback method) */ estimatePageNumber(element) { try { if (!element) return 3; const rect = element.getBoundingClientRect(); const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const absoluteTop = rect.top + scrollTop; // A4 page height in pixels (assuming 96 DPI) // A4 = 210mm x 297mm, 1 inch = 25.4mm, 1 inch = 96 pixels const pageHeightPixels = (297 * 96) / 25.4; // ~1123 pixels per page // Account for margins and spacing - use actual content height const effectivePageHeight = pageHeightPixels - 150; // More realistic margin // Calculate page number (start from page 3 since pages 1-2 are title and TOC) let pageNumber = Math.floor(absoluteTop / effectivePageHeight) + 3; // Don't clamp - let it go to actual page count console.log(`๐Ÿ“„ Element "${element.textContent.trim()}" at position ${absoluteTop}px = page ${pageNumber}`); return pageNumber; } catch (error) { console.warn('Error estimating page number:', error); return 3; // Default fallback } } /** * Create a TOC entry element */ createTOCEntry(heading) { const entry = document.createElement('div'); entry.className = `toc-entry toc-level-${heading.level}`; // Create the text content const textSpan = document.createElement('span'); textSpan.className = 'toc-text'; textSpan.textContent = heading.text; // Create the dots area (now just spacing) const dotsSpan = document.createElement('span'); dotsSpan.className = 'dots'; // Create the page number const pageSpan = document.createElement('span'); pageSpan.className = 'toc-page'; pageSpan.textContent = heading.page; // Assemble the entry entry.appendChild(textSpan); entry.appendChild(dotsSpan); entry.appendChild(pageSpan); // Add click functionality to jump to heading entry.addEventListener('click', () => { heading.element.scrollIntoView({ behavior: 'smooth' }); }); return entry; } /** * Setup dynamic updates */ setupDynamicUpdates() { // Refresh TOC when window is resized window.addEventListener('resize', () => { setTimeout(() => this.refresh(), 100); }); // Refresh TOC when content changes const observer = new MutationObserver(() => { this.refresh(); }); // Observe the main content area const mainContent = document.querySelector('.main-content'); if (mainContent) { observer.observe(mainContent, { childList: true, subtree: true, characterData: true }); } } /** * Refresh the TOC */ async refresh() { await this.loadPageNumbers(); this.generateTOC(); } /** * Estimate page number based on element position */ estimatePageNumber(element) { const pageHeightPixels = 1123; // A4 height in pixels at 96 DPI const absoluteTop = element.offsetTop; const estimatedPage = Math.floor(absoluteTop / pageHeightPixels) + 1; console.log(`๐Ÿ“ Element "${element.textContent.trim()}" at position ${absoluteTop}px -> estimated page ${estimatedPage}`); return estimatedPage; } /** * Get total page count for footer updates */ getTotalPages() { return this.totalPages; } } // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', function() { console.log('๐Ÿš€ TOC Generator: DOM loaded, starting...'); // Wait for numbering script to finish setTimeout(() => { console.log('๐Ÿ”„ TOC Generator: Creating instance...'); window.tocGenerator = new TOCGenerator(); window.tocGenerator.init(); }, 100); }); // Also try immediate execution as fallback console.log('๐Ÿ“œ TOC Generator script loaded'); // Simple test - if this shows up, JavaScript is working document.addEventListener('DOMContentLoaded', function() { console.log('๐Ÿงช SIMPLE TEST: JavaScript is working!'); // Test if we can find the TOC container const tocContainer = document.querySelector('.toc-auto'); if (tocContainer) { console.log('โœ… Found TOC container:', tocContainer); // Don't overwrite the TOC content - just log that we found it } else { console.log('โŒ TOC container NOT found'); } });