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 ===');
        
        function startTracker() {
            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,
                maxRetries : 30,
                retryDelay : 300
            };
    
            var panel = document.getElementById('trackerPageContent');
            var list  = document.getElementById('trackerList');
    
            if (!panel || !list) {
                console.error('Panel or list not found!');
                return;
            }
    
            var headings = [];
            var currentIndex = -1;
            var timer;
            var scrollCount = 0;
    
            function collectHeadings() {
                var seenTexts = [];
                var allHeadings = document.querySelectorAll(CONFIG.selectors);
                var tempHeadings = [];
                
                for (var i = 0; i < allHeadings.length; i++) {
                    var h = allHeadings[i];
                    var excluded = false;
                    
                    for (var j = 0; j < CONFIG.excludeContainers.length; j++) {
                        var container = document.querySelector(CONFIG.excludeContainers[j]);
                        if (container && container.contains(h)) {
                            excluded = true;
                            break;
                        }
                    }
                    
                    if (excluded) continue;
                    
                    var text = h.textContent || h.innerText;
                    text = text.replace(/^\s+|\s+$/g, '');
                    
                    var duplicate = false;
                    for (var m = 0; m < seenTexts.length; m++) {
                        if (seenTexts[m] === text) {
                            duplicate = true;
                            break;
                        }
                    }
                    
                    if (!duplicate) {
                        seenTexts.push(text);
                        tempHeadings.push({ el: h, text: text });
                    }
                }
                
                headings = tempHeadings;
                console.log('Found ' + headings.length + ' headings');
            }
    
            function getTop(el) {
                var rect = el.getBoundingClientRect();
                var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
                return rect.top + scrollTop;
            }
    
            function findCurrent() {
                if (headings.length === 0) 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() {
                list.innerHTML = '';
                if (headings.length === 0) 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.className = 'tracker-item';
                    
                    if (i === currentIndex) {
                        item.className = item.className + ' current';
                    } else if (Math.abs(i - currentIndex) === 1) {
                        item.className = item.className + ' near';
                    } else {
                        item.className = item.className + ' far';
                    }
                    
                    item.appendChild(document.createTextNode(headings[i].text));
                    list.appendChild(item);
                }
            }
    
            function update() {
                if (headings.length === 0) return;
                
                var idx = findCurrent();
                console.log('Update: old=' + currentIndex + ', new=' + idx);
                
                if (idx !== currentIndex) {
                    currentIndex = idx;
                    render();
                }
            }
    
            function onScroll() {
                scrollCount++;
                console.log('SCROLL EVENT #' + scrollCount);
                clearTimeout(timer);
                timer = setTimeout(update, CONFIG.throttle);
            }
    
            console.log('Attaching scroll listener...');
            if (window.addEventListener) {
                window.addEventListener('scroll', onScroll, false);
                window.addEventListener('resize', update, false);
                console.log('addEventListener used');
            } else if (window.attachEvent) {
                window.attachEvent('onscroll', onScroll);
                window.attachEvent('onresize', update);
                console.log('attachEvent used (IE)');
            }
    
            function init(attempt) {
                collectHeadings();
                
                if (headings.length > 0) {
                    currentIndex = findCurrent();
                    console.log('Initial render at index: ' + currentIndex);
                    render();
                    return;
                }
                
                if (attempt < CONFIG.maxRetries) {
                    setTimeout(function() {
                        init(attempt + 1);
                    }, CONFIG.retryDelay);
                }
            }
    
            setTimeout(function() {
                init(0);
            }, 1000);
        }
    
        if (document.readyState === 'loading') {
            if (document.addEventListener) {
                document.addEventListener('DOMContentLoaded', startTracker, false);
            }
        } else {
            startTracker();
        }
    })();
    
    <div id="trackerPageContent">
     <div class="tracker-list" id="trackerList"></div>
    </div>
    #trackerPageContent {
        position: fixed;
        bottom: 110px;
        left: 20px;
        width: 250px;
        z-index: 2147483000;
        pointer-events: none;
        opacity: 1;
    }
    
    .tracker-list {
        display: flex;
        flex-direction: column;
        gap: 6px;
    }
    
    .tracker-item {
        line-height: 1.35;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    
    .tracker-item.current {
        font-size: 22px;
        font-weight: 600;
        color: #0066CC;
    }
    
    .tracker-item.near {
        font-size: 16px;
        color: #777777;
    }
    
    .tracker-item.far {
        font-size: 14px;
        color: #7777776b;
    }
    

     
    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 :-)