dynamic-toc

Von $1

    Inhaltsverzeichnis
    keine Gliederung

    Version seit 15:43, 5 Nov 2026

    zu dieser Version.

    Zurück zu Versionshistorie.

    Zeige aktuelle Version

    (function () {
        console.log('=== TRACKER START ===');
        
        if (document.getElementById('trackerPageContent')) {
            console.log('ERROR: Tracker already exists!');
            return;
        }
    
        var CONFIG = {
            selectors: 'h2, h3, h4',
            threshold: 0.35,
            throttle: 80,
            range: 2,
            excludeTexts: ['Von $1', '*Edit'],
            excludeContainers: ['.deki-page-titlex', '#siteSubx'],
            bottomDefault: 110,
            bottomMenuOpen: 300
        };
    
        // Create elements
        var panel = document.createElement('div');
        panel.id = 'trackerPageContent';
        panel.style.cssText = 'position:fixed;bottom:110px;left:20px;width:250px;z-index:9999999;pointer-events:none;background:rgba(255,0,0,0.3);padding:10px;opacity:1';
        
        var list = document.createElement('div');
        list.id = 'trackerList';
        list.style.cssText = 'display:flex;flex-direction:column;gap:6px';
        
        panel.appendChild(list);
        document.body.appendChild(panel);
        console.log('✓ Panel created and added to body');
    
        var headings = [];
        var currentIndex = -1;
        var timer;
    
        function collectHeadings() {
            console.log('--- Collecting headings ---');
            var all = document.querySelectorAll(CONFIG.selectors);
            console.log('Found ' + all.length + ' total headings');
            
            var seenTexts = [];
            headings = Array.from(all)
                .filter(function (h) {
                    for (var i = 0; i < CONFIG.excludeContainers.length; i++) {
                        if (h.closest(CONFIG.excludeContainers[i])) return false;
                    }
                    return true;
                })
                .map(function (h) {
                    return { el: h, text: h.textContent.trim() };
                })
                .filter(function (h) {
                    for (var i = 0; i < CONFIG.excludeTexts.length; i++) {
                        var pattern = CONFIG.excludeTexts[i];
                        if (pattern.startsWith('*') && h.text.endsWith(pattern.substring(1))) return false;
                        if (pattern.endsWith('*') && h.text.startsWith(pattern.slice(0, -1))) return false;
                        if (h.text === pattern) return false;
                    }
                    if (seenTexts.includes(h.text)) return false;
                    seenTexts.push(h.text);
                    return true;
                });
            
            console.log('After filtering: ' + headings.length + ' headings');
            headings.forEach(function(h, i) {
                console.log('  [' + i + '] ' + h.text.substring(0, 40));
            });
        }
    
        function getTop(el) {
            var rect = el.getBoundingClientRect();
            return rect.top + (window.pageYOffset || document.documentElement.scrollTop);
        }
    
        function findCurrent() {
            if (!headings.length) return 0;
            var scrollPos = window.pageYOffset || document.documentElement.scrollTop;
            var triggerPoint = scrollPos + (window.innerHeight * CONFIG.threshold);
            
            for (var i = headings.length - 1; i >= 0; i--) {
                var top = getTop(headings[i].el);
                if (triggerPoint >= top) {
                    return i;
                }
            }
            return 0;
        }
    
        function render() {
            console.log('RENDER at index: ' + currentIndex);
            list.innerHTML = '';
            if (!headings.length) {
                list.innerHTML = '<div style="color:red">NO HEADINGS!</div>';
                return;
            }
            
            var start = Math.max(0, currentIndex - CONFIG.range);
            var end = Math.min(headings.length - 1, currentIndex + CONFIG.range);
            
            for (var i = start; i <= end; i++) {
                var item = document.createElement('div');
                item.style.cssText = 'line-height:1.35;white-space:nowrap;overflow:hidden;text-overflow:ellipsis';
                
                if (i === currentIndex) {
                    item.style.fontSize = '22px';
                    item.style.fontWeight = '600';
                    item.style.color = '#06C';
                } else if (Math.abs(i - currentIndex) === 1) {
                    item.style.fontSize = '16px';
                    item.style.color = '#777';
                } else {
                    item.style.fontSize = '14px';
                    item.style.color = '#999';
                }
                
                item.textContent = headings[i].text;
                list.appendChild(item);
            }
        }
    
        function update() {
            if (!headings.length) return;
            var idx = findCurrent();
            if (idx !== currentIndex) {
                currentIndex = idx;
                render();
            }
        }
    
        window.addEventListener('scroll', function () {
            clearTimeout(timer);
            timer = setTimeout(update, CONFIG.throttle);
        }, { passive: true });
    
        function init(attempt) {
            console.log('INIT attempt #' + (attempt + 1));
            collectHeadings();
            
            if (headings.length > 0) {
                console.log('✓ SUCCESS - found headings!');
                currentIndex = findCurrent();
                render();
                return;
            }
            
            if (attempt < 30) {
                console.log('No headings yet, retrying...');
                setTimeout(function() {
                    init(attempt + 1);
                }, 500);
            } else {
                console.log('✗ FAILED after 30 attempts');
                list.innerHTML = '<div style="color:red">FAILED TO FIND HEADINGS</div>';
            }
        }
    
        setTimeout(function() {
            init(0);
        }, 2000);
    })();
    

     
    Use the language selection below for English Utilise le sélecteur de langue ci-dessous pour français Per l'italiano, utilizzare la selezione della lingua qui sotto Schön sprichst du deutsch :-)