/** * Contents Control - Displays document table of contents * Implements the Robustness Principle with Fail Fast mode support */ class ContentsControl { constructor() { this.control = Object.create(Control); this.control.config = { icon: '☰', title: 'Contents', className: 'contents-control', defaultContent: 'Click to view table of contents', ariaLabel: 'Contents Control', position: 'w' }; // Bind methods to control this.control.buildContent = () => { const content = this.control.element.querySelector('.control-content'); const headings = this.extractHeadings(); content.innerHTML = `

Table of Contents

${headings.length > 0 ? headings.map(heading => `
${heading.text}
` ).join('') : '

No headings found in document

' }
${headings.length} heading${headings.length !== 1 ? 's' : ''} found
`; this.control.isExpanded = true; }; this.control.toggle = () => { if (this.control.isExpanded) { this.control.element.querySelector('.control-content').style.display = 'none'; this.control.isExpanded = false; } else { this.control.buildContent(); this.control.element.querySelector('.control-content').style.display = 'block'; } }; } extractHeadings() { const headings = []; const elements = document.querySelectorAll('h1, h2, h3, h4, h5, h6'); elements.forEach((heading, index) => { const level = parseInt(heading.tagName.charAt(1)); const text = heading.textContent || heading.innerText || ''; let id = heading.id; // Generate ID if not present if (!id) { id = text.toLowerCase() .replace(/[^\w\s-]/g, '') .replace(/\s+/g, '-') .replace(/-+/g, '-') .replace(/^-|-$/g, '') || `heading-${index}`; heading.id = id; } headings.push({ level: level, text: text.trim(), id: id }); }); return headings; } createControl() { return this.control.createControl(); } } window.ContentsControl = ContentsControl;