MediaWiki:Common.js: Unterschied zwischen den Versionen

Keine Bearbeitungszusammenfassung
Markierung: Manuelle Zurücksetzung
Keine Bearbeitungszusammenfassung
 
(39 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
/* === PREPRINT START === */
/* === PREPRINT START === */
/* ============================================
/* ============================================
   PREPRINT v7.17 - JS v260212r7
   PREPRINT v7.17 - JS v260225r1
 
  ARCHITECTURE:
  - Platform Adaptation Layer (PAL): isolates Minerva workarounds
  - Model Layer: dimensional intent, linkage fabric, projection
  - Feature Layer: BookNav, TOC, Snippets
   ============================================ */
   ============================================ */


Zeile 14: Zeile 9:
     // Prevent repeated initialization
     // Prevent repeated initialization
     if (window.preprintInitialized) {
     if (window.preprintInitialized) {
        console.log('Preprint: Already initialized, skipping');
         return;
         return;
     }
     }
Zeile 35: Zeile 29:
         var imagesStabilized = false;
         var imagesStabilized = false;
          
          
         // Debug logging with source tracking
         // Debug logging with source tracking (silent in production)
         function log(adapter, message) {
         function log(adapter, message) {
            console.log('Preprint PAL.' + adapter + ': ' + message);
         }
         }


Zeile 52: Zeile 45:
                 }
                 }
                  
                  
                New:
                 // Minerva: observe mutations, unwrap sections as they appear
                 // Minerva: observe mutations, unwrap sections as they appear
                 var debounceTimer = null;
                 var debounceTimer = null;
Zeile 330: Zeile 322:
                 var myGeneration = ++transitionGeneration;
                 var myGeneration = ++transitionGeneration;
                  
                  
                New:
                 resizeTimer = setTimeout(function() {
                 resizeTimer = setTimeout(function() {
                     setOrientationClass(targetOrientation);
                     setOrientationClass(targetOrientation);
Zeile 472: Zeile 463:
                     initViewport();
                     initViewport();
                      
                      
                    New:
                     waitForDOMStability()
                     waitForDOMStability()
                         .then(function() {
                         .then(function() {
Zeile 574: Zeile 564:
         function getLinkage() {
         function getLinkage() {
             return linkage;
             return linkage;
        }
        /* --- List Repair --- */
       
        // MW parser ejects template-generated spans (Place) from list items:
        //  Pattern A (start): <li class="mw-empty-elt"/> + <p><span>...</span>text</p>
        //  Pattern B (end):  <li>text</li> + <p><span>...</span></p>
        // Both followed optionally by a continuation list.
        // This repairs the DOM before structure analysis.
        function repairListPlacement() {
            var $output = $('.mw-parser-output');
            if (!$output.length) return;
            var repaired = 0;
           
            function findEmptyItem($list) {
                var $li = $list.find('li.mw-empty-elt').last();
                if ($li.length) return $li;
                var $dd = $list.find('dd').filter(function() {
                    return this.childNodes.length === 0;
                }).last();
                return $dd.length ? $dd : null;
            }
           
            function isNestingWrapper(el) {
                if (el.tagName !== 'LI') return false;
                if (el.children.length !== 1) return false;
                if (!/^(UL|OL|DL)$/.test(el.firstElementChild.tagName)) return false;
                for (var i = 0; i < el.childNodes.length; i++) {
                    if (el.childNodes[i].nodeType === 3 && el.childNodes[i].textContent.trim()) return false;
                }
                return true;
            }
           
            $output.find('p').each(function() {
                var p = this;
                if (!p.parentNode) return;
                var first = p.firstChild;
                if (!first || first.nodeType !== 1) return;
                if (!first.classList.contains('place-lh') && !first.classList.contains('place-oc')) return;
               
                var $p = $(p);
                var $prevList = $p.prev('ul, ol, dl');
                if (!$prevList.length) return;
               
                // Pattern A: empty item (Place at start of list item)
                var $target = findEmptyItem($prevList);
                var isPatternA = $target !== null;
               
                // Pattern B: no empty item (Place at end of list item)
                if (!$target) {
                    $target = $prevList.find('li').last();
                    if (!$target.length) $target = $prevList.find('dd').last();
                    if (!$target.length) return;
                }
               
                if (isPatternA) $target.removeClass('mw-empty-elt');
               
                // Move <p> contents into target item
                while (p.firstChild) {
                    $target[0].appendChild(p.firstChild);
                }
               
                // Merge continuation list if same type follows
                var $next = $p.next();
                if ($next.length && $next[0].tagName === $prevList[0].tagName) {
                    var targetAtRoot = $target[0].parentNode === $prevList[0];
                   
                    var children = $next.children().get();
                    for (var i = 0; i < children.length; i++) {
                        if (isNestingWrapper(children[i])) {
                            var subList = children[i].firstElementChild;
                            if (targetAtRoot) {
                                // Pattern B: sub-list becomes child of target
                                $target[0].appendChild(subList);
                            } else {
                                // Pattern A: sub-list items become siblings
                                var parentList = $target[0].parentNode;
                                while (subList.firstChild) {
                                    parentList.appendChild(subList.firstChild);
                                }
                            }
                        } else {
                            $prevList[0].appendChild(children[i]);
                        }
                    }
                    $next.remove();
                }
               
                $p.remove();
                repaired++;
            });
           
         }
         }


Zeile 579: Zeile 661:
          
          
         function buildStructure() {
         function buildStructure() {
            repairListPlacement();
             var parserOutput = $('.mw-parser-output');
             var parserOutput = $('.mw-parser-output');
             var elements = parserOutput.children().toArray();
             var elements = parserOutput.children().toArray();
Zeile 665: Zeile 748:
                 }
                 }
             });
             });
           
                       
            console.log('Preprint Model: Structure built, ' + linkage.length + ' linkages');
           
             // Helper functions (closure)
             // Helper functions (closure)
             function ensureColumns() {
             function ensureColumns() {
Zeile 709: Zeile 790:
             if (layout && layout[0]) layout[0].style.paddingBottom = '';
             if (layout && layout[0]) layout[0].style.paddingBottom = '';
             $('.preprint-oc-spacer').remove();
             $('.preprint-oc-spacer').remove();
             // Clear inline positioning
             // Clear inline positioning set by landscape projection
             linkage.forEach(function(link) {
             linkage.forEach(function(link) {
                link.element[0].style.top = '';
                 link.element[0].style.position = '';
                 link.element[0].style.position = '';
                link.element[0].style.top = '';
             });
             });
              
              
Zeile 765: Zeile 846:
              
              
             scrollToHash();
             scrollToHash();
            console.log('Preprint Model: Portrait projection applied');
         }
         }
          
          
Zeile 789: Zeile 869:
             }
             }
              
              
             positionOCElements();
             reconcileLayout();
              
              
             // Restore scroll
             // Restore scroll
Zeile 796: Zeile 876:
              
              
             scrollToHash();
             scrollToHash();
            console.log('Preprint Model: Landscape projection applied');
         }
         }
          
          
         function positionOCElements() {
         function reconcileLayout() {
             // Force reflow
            if (!document.body.classList.contains('preprint-landscape')) return;
             if (layout && layout[0]) {
            if (reconcileLayout._running) return;
                void layout[0].offsetHeight;
            reconcileLayout._running = true;
            }
           
            // Disconnect observer to prevent re-entry from our writes
            if (layout._ocObserver) layout._ocObserver.disconnect();
            // Save and reset scroll for accurate offset calculations (Minerva scrolls body)
            var savedBodyScroll = document.body.scrollTop;
            var savedHtmlScroll = document.documentElement.scrollTop;
            document.body.scrollTop = 0;
            document.documentElement.scrollTop = 0;
 
             // === PHASE 1: CLEAN + READ ===
           
            // Remove all previous-cycle artifacts
            $('.preprint-oc-spacer').remove();
             if (layout && layout[0]) layout[0].style.paddingBottom = '';
              
              
            // Position each element relative to its marker
             linkage.forEach(function(link) {
             linkage.forEach(function(link) {
                 var $marker = link.marker;
                 if (link.element[0].style.position !== 'absolute') {
                var $element = link.element;
                    link.element[0].style.position = 'absolute';
                 var $oc = $element.closest('.outer-column');
                    link.element[0].style.top = '0px';
               
                }
                 if (!$oc.length) return;
            });
               
           
                var markerOffset = $marker.offset();
            // Force reflow after cleanup
                var ocOffset = $oc.offset();
            void document.body.offsetHeight;
               
                       
                if (!markerOffset || !ocOffset) return;
            // Read marker positions, OC container offsets, element geometry
            var items = [];
            linkage.forEach(function(link, i) {
                 var $oc = link.element.closest('.outer-column');
                 if (!$oc.length) { items.push(null); return; }
                  
                  
                 var relativeTop = markerOffset.top - ocOffset.top;
                 var markerTop = link.marker.offset().top;
                var ocTop = $oc.offset().top;
                  
                  
                 $element.css({
                 items.push({
                     'position': 'absolute',
                    index: i,
                     'top': relativeTop + 'px'
                    link: link,
                    markerTop: markerTop,
                    ocTop: ocTop,
                    ocEl: $oc[0],
                    height: link.element.outerHeight(true),
                     margin: parseFloat(link.element.css('margin-top')) || 0,
                    landscapeDir: link.element.attr('data-landscape') || null,
                     top: markerTop - ocTop,
                    docTop: markerTop
                 });
                 });
             });
             });
              
              
             // Landscape placement overrides (elevator)
             // Read first visible IC child offset per OC container (for elevator)
             var landscapeOverrides = linkage.filter(function(link) {
             var ocContainers = [];
                return link.element.attr('data-landscape');
             var ocFirstICTop = [];
             });
            $('.outer-column').each(function() {
            if (landscapeOverrides.length > 0) {
                ocContainers.push(this);
                landscapeOverrides.forEach(function(link) {
                var $ic = $(this).prev('.inner-column');
                    var dir = link.element.attr('data-landscape');
                if (!$ic.length) { ocFirstICTop.push(0); return; }
                    var $oc = link.element.closest('.outer-column');
                var ocTop = $(this).offset().top;
                    if (!$oc.length) return;
                var found = false;
                    var myTop = parseFloat(link.element.css('top')) || 0;
                $ic.children().each(function() {
                   
                    if (this.getBoundingClientRect().height > 0) {
                    // Collect siblings in same column (excluding self), document-relative
                        ocFirstICTop.push($(this).offset().top - ocTop);
                    var ocOffset = $oc.offset().top;
                         found = true;
                    var siblings = [];
                         return false;
                    $oc.children('.place-oc, .place-lh, .preprint-table-oc-wrapper').each(function() {
                        var $el = $(this);
                        if ($el[0] === link.element[0]) return;
                        var rect = this.getBoundingClientRect();
                        var scrollY = window.pageYOffset || document.documentElement.scrollTop;
                        siblings.push({
                            el: $el,
                            top: rect.top + scrollY - ocOffset,
                            bottom: rect.bottom + scrollY - ocOffset
                        });
                    });
                    siblings.sort(function(a, b) { return a.top - b.top; });
                   
                    if (dir === 'top') {
                        // Find nearest sibling above
                        var above = null;
                        for (var i = siblings.length - 1; i >= 0; i--) {
                            if (siblings[i].top < myTop) { above = siblings[i]; break; }
                        }
                        var margin = parseFloat(link.element.css('margin-top')) || 0;
                        if (above) {
                            link.element.css('top', (above.bottom - margin) + 'px');
                        } else {
                            // No sibling above: align with first visible IC content
                            var $ic = $oc.prev('.inner-column');
                            var targetTop = 0;
                            if ($ic.length) {
                                $ic.children().each(function() {
                                    if (this.getBoundingClientRect().height > 0) {
                                        targetTop = this.getBoundingClientRect().top - $oc[0].getBoundingClientRect().top - margin;
                                        return false;
                                    }
                                });
                            }
                            link.element.css('top', targetTop + 'px');
                         }
                    } else if (dir === 'bottom') {
                        // Find nearest sibling below
                        var below = null;
                         for (var i = 0; i < siblings.length; i++) {
                            if (siblings[i].top > myTop) { below = siblings[i]; break; }
                        }
                        if (below) {
                            link.element.css('top', (below.top - link.element.outerHeight(true)) + 'px');
                        }
                        // If none below, stays at marker position (already at bottom)
                     }
                     }
                 });
                 });
            }
                 if (!found) ocFirstICTop.push(0);
           
            // Fix overlaps
            fixOverlaps();
            // Correct OC position to align with adjacent IC content
            linkage.forEach(function(link) {
                var nextIC = link.marker[0].nextElementSibling;
                 if (!nextIC) return;
                // Only correct for block-level siblings (tables, divs), not inline elements within a paragraph
                if (nextIC.parentNode && nextIC.parentNode.tagName === 'P') return;
                var ocEl = link.element[0];
                var icInner = nextIC.querySelector('table') || nextIC;
                var ocInner = ocEl.querySelector('table') || ocEl;
                var delta = icInner.getBoundingClientRect().top - ocInner.getBoundingClientRect().top;
                if (Math.abs(delta) > 1) {
                    var current = parseFloat(link.element.css('top')) || 0;
                    link.element.css('top', (current + delta) + 'px');
                }
             });
             });
            syncOCtoIC();
            adjustLayoutPadding();
              
              
             // Watch for collapsible table expand/collapse
             // Read protruding IC elements
             if (!layout._ocObserver) {
             var protrusions = [];
                 layout._ocObserver = new MutationObserver(function() {
            $('.inner-column').each(function() {
                     fixOverlaps();
                 var icWidth = this.getBoundingClientRect().width;
                     syncOCtoIC();
                $(this).children().each(function() {
                     adjustLayoutPadding();
                     if (this.classList.contains('oc-marker')) return;
                     var elWidth = this.scrollWidth || this.getBoundingClientRect().width;
                     if (elWidth > icWidth + 1) {
                        var top = $(this).offset().top;
                        protrusions.push({
                            element: this,
                            top: top,
                            bottom: top + this.getBoundingClientRect().height
                        });
                    }
                 });
                 });
                layout._ocObserver.observe(layout[0], { subtree: true, attributes: true, attributeFilter: ['class'] });
             });
             }
        }
       
        function fixOverlaps() {
            // Force reflow first
            void document.body.offsetHeight;
              
              
             // Collect elements with document-relative positions
             // === PHASE 2: COMPUTE (no DOM access) ===
            var scrollY = window.pageYOffset || document.documentElement.scrollTop;
            var allOC = [];
            $('.outer-column').each(function() {
                var $oc = $(this);
                $oc.children('.place-oc, .place-lh, .preprint-table-oc-wrapper').each(function() {
                    var $el = $(this);
                    var rect = this.getBoundingClientRect();
                    allOC.push({
                        el: $el,
                        oc: $oc,
                        top: rect.top + scrollY,
                        bottom: rect.bottom + scrollY
                    });
                });
            });
 
            // Sort by document-relative top
            allOC.sort(function(a, b) { return a.top - b.top; });
              
              
             // Fix overlaps using document-relative positions
             // Elevator adjustments
             var lastBottom = 0;
             items.forEach(function(item) {
            allOC.forEach(function(item, index) {
                 if (!item || !item.landscapeDir) return;
                var overlap = lastBottom - item.top;
                 if (overlap > 0) {
                    // Push down by overlap amount
                    var currentTop = parseFloat(item.el.css('top')) || 0;
                    item.el.css('top', (currentTop + overlap) + 'px');
                    item.top += overlap;
                    item.bottom += overlap;
                }
                  
                  
                // Gap 4px
                 var siblings = items.filter(function(other) {
                 var nextIsTable = (index + 1 < allOC.length) &&
                    return other && other.ocEl === item.ocEl && other.index !== item.index;
                    allOC[index + 1].el.hasClass('preprint-table-oc-wrapper');
                }).sort(function(a, b) { return a.top - b.top; });
                var gap = 4;
                  
                  
                 lastBottom = item.bottom + gap;
                 if (item.landscapeDir === 'top') {
                    var above = null;
                    for (var i = siblings.length - 1; i >= 0; i--) {
                        if (siblings[i].top < item.top) { above = siblings[i]; break; }
                    }
                    if (above) {
                        item.top = above.top + above.height - item.margin;
                    } else {
                        var ocIdx = ocContainers.indexOf(item.ocEl);
                        if (ocIdx >= 0) {
                            item.top = ocFirstICTop[ocIdx] - item.margin;
                        }
                    }
                } else if (item.landscapeDir === 'bottom') {
                    var below = null;
                    for (var i = 0; i < siblings.length; i++) {
                        if (siblings[i].top > item.top) { below = siblings[i]; break; }
                    }
                    if (below) {
                        item.top = below.top - item.height;
                    }
                }
                item.docTop = item.ocTop + item.top;
             });
             });
        }
        function syncOCtoIC() {
            $('.preprint-oc-spacer').remove();
              
              
             if (!document.body.classList.contains('preprint-landscape')) return;
             // Fix overlaps (type-pair minimum gaps)
            var valid = items.filter(function(item) { return item !== null; });
            valid.sort(function(a, b) { return a.docTop - b.docTop; });
           
            function elementGap(item) {
                if (item.link.type === 'place-lh') return 2;
                if (item.height >= 50) return 16;
                return 4;
            }
              
              
             var scrollY = window.pageYOffset || document.documentElement.scrollTop;
             var lastItem = null;
            valid.forEach(function(item) {
                if (lastItem) {
                    var minGap = Math.max(elementGap(item), elementGap(lastItem));
                    var requiredTop = lastItem.docTop + lastItem.height + minGap;
                    var overlap = requiredTop - item.docTop;
                    if (overlap > 0) {
                        item.top += overlap;
                        item.docTop += overlap;
                    }
                }
                lastItem = item;
            });
              
              
             // Collect ALL OC elements globally
             // Conflict detection: protruding IC vs computed OC positions
             var ocElements = [];
             var spacers = [];
             $('.outer-column').children('.place-oc, .place-lh, .preprint-table-oc-wrapper').each(function() {
             protrusions.forEach(function(prot) {
                 var rect = this.getBoundingClientRect();
                 var maxConflictBottom = 0;
                 ocElements.push({
                 valid.forEach(function(item) {
                     top: rect.top + scrollY,
                     var ocBottom = item.docTop + item.height;
                     bottom: rect.bottom + scrollY
                     if (prot.top < ocBottom && prot.bottom > item.docTop) {
                        if (ocBottom > maxConflictBottom) maxConflictBottom = ocBottom;
                    }
                 });
                 });
                if (maxConflictBottom > 0) {
                    var pushdown = maxConflictBottom - prot.top;
                    if (pushdown > 0) {
                        spacers.push({ element: prot.element, height: pushdown });
                    }
                }
             });
             });
            if (ocElements.length === 0) return;
              
              
             $('.inner-column').each(function() {
             // === PHASE 3: WRITE (single pass) ===
                var $ic = $(this);
           
                var icWidth = $ic[0].getBoundingClientRect().width;
            // Set OC positions
               
            valid.forEach(function(item) {
                $ic.children().each(function() {
                item.link.element.css({
                    if (this.classList.contains('oc-marker')) return;
                    'position': 'absolute',
                    if (this.classList.contains('preprint-oc-spacer')) return;
                    'top': item.top + 'px'
                   
                    var elWidth = this.scrollWidth || this.getBoundingClientRect().width;
                    if (elWidth <= icWidth + 1) return;
                   
                    var rect = this.getBoundingClientRect();
                    var elTop = rect.top + scrollY;
                    var elBottom = rect.bottom + scrollY;
                   
                    var maxConflictBottom = 0;
                    ocElements.forEach(function(oc) {
                        if (elTop < oc.bottom && elBottom > oc.top) {
                            if (oc.bottom > maxConflictBottom) maxConflictBottom = oc.bottom;
                        }
                    });
                   
                    if (maxConflictBottom > 0) {
                        var pushdown = maxConflictBottom - elTop;
                        if (pushdown > 0) {
                            var spacer = document.createElement('div');
                            spacer.className = 'preprint-oc-spacer';
                            spacer.style.height = pushdown + 'px';
                            this.parentNode.insertBefore(spacer, this);
                        }
                    }
                 });
                 });
             });
             });
        }
           
 
            // Insert spacers
        function adjustLayoutPadding() {
            spacers.forEach(function(s) {
            var el = document.querySelector('.preprint-layout');
                var spacer = document.createElement('div');
             if (!el) return;
                spacer.className = 'preprint-oc-spacer';
             var layoutRect = el.getBoundingClientRect();
                spacer.style.height = s.height + 'px';
             var currentPad = parseFloat(el.style.paddingBottom || 0);
                s.element.parentNode.insertBefore(spacer, s.element);
             var maxBottom = 0;
             });
             $('.outer-column .place-oc, .outer-column .place-lh, .outer-column .preprint-table-oc-wrapper').each(function() {
              
                 var rect = this.getBoundingClientRect();
            // Final measure: layout padding
                 if (rect.bottom > maxBottom) maxBottom = rect.bottom;
            void document.body.offsetHeight;
             var scrollY = window.pageYOffset || 0;
            var layoutBottom = layout[0].getBoundingClientRect().bottom + scrollY;
             var maxOCBottom = 0;
             valid.forEach(function(item) {
                 var rect = item.link.element[0].getBoundingClientRect();
                 if (rect.bottom + scrollY > maxOCBottom) maxOCBottom = rect.bottom + scrollY;
            });
            if (maxOCBottom > layoutBottom) {
                layout[0].style.paddingBottom = (maxOCBottom - layoutBottom) + 'px';
            }
           
            // Restore scroll
            document.body.scrollTop = savedBodyScroll;
            document.documentElement.scrollTop = savedHtmlScroll;
            reconcileLayout._running = false;
           
            // Reconnect or create observer
            if (!layout._ocObserver) {
                layout._ocObserver = new MutationObserver(function() {
                    clearTimeout(layout._ocDebounce);
                    layout._ocDebounce = setTimeout(reconcileLayout, 300);
                });
            }
            layout._ocObserver.observe(layout[0], {
                subtree: true, attributes: true, attributeFilter: ['class']
             });
             });
             var overflow = maxBottom - layoutRect.bottom + currentPad;
              
             if (overflow > 0) {
            // ResizeObserver: catches container width changes not visible to
                 el.style.paddingBottom = overflow + 'px';
            // window resize (TOC pin/unpin, tool menu toggle, DevTools panel).
            // Created once, never disconnected — only fires on actual size change.
             if (!layout._resizeObserver && typeof ResizeObserver !== 'undefined') {
                 layout._resizeObserver = new ResizeObserver(function() {
                    clearTimeout(layout._resizeDebounce);
                    layout._resizeDebounce = setTimeout(function() {
                        if (PAL.isOrientationLocked()) return;
                        if (document.body.classList.contains('preprint-landscape')) {
                            reconcileLayout();
                        }
                    }, 200);
                });
                layout._resizeObserver.observe(layout[0]);
             }
             }
         }
         }
Zeile 1.038: Zeile 1.111:
         $('.preprint-layout img').on('load', function() {
         $('.preprint-layout img').on('load', function() {
             if (document.body.classList.contains('preprint-landscape')) {
             if (document.body.classList.contains('preprint-landscape')) {
                 positionOCElements();
                 reconcileLayout();
             }
             }
         });
         });
Zeile 1.049: Zeile 1.122:
                     if (PAL.isOrientationLocked()) return;
                     if (PAL.isOrientationLocked()) return;
                     if (document.body.classList.contains('preprint-landscape')) {
                     if (document.body.classList.contains('preprint-landscape')) {
                         positionOCElements();
                         reconcileLayout();
                     }
                     }
                 }, 200);
                 }, 200);
Zeile 1.062: Zeile 1.135:
                     el.scrollIntoView({ block: 'start' });
                     el.scrollIntoView({ block: 'start' });
                     window.scrollBy(0, -60);
                     window.scrollBy(0, -60);
                    console.log('Preprint Model: Scrolled to return target ' + returnTarget);
                 }
                 }
                 returnTarget = null;
                 returnTarget = null;
Zeile 1.074: Zeile 1.146:
                 target.scrollIntoView({ block: 'start' });
                 target.scrollIntoView({ block: 'start' });
                 window.scrollBy(0, -60);
                 window.scrollBy(0, -60);
                console.log('Preprint Model: Scrolled to hash ' + window.location.hash);
             }
             }
         }
         }
Zeile 1.187: Zeile 1.258:
             getLinkage: getLinkage,
             getLinkage: getLinkage,
             applyProjection: applyProjection,
             applyProjection: applyProjection,
             positionOCElements: positionOCElements,
             positionOCElements: reconcileLayout,
             captureAnchor: captureAnchor,
             captureAnchor: captureAnchor,
             restoreAnchor: restoreAnchor,
             restoreAnchor: restoreAnchor,
             getPositionAnchor: getPositionAnchor,
             getPositionAnchor: getPositionAnchor,
             getLayout: function() { return layout; },
             getLayout: function() { return layout; },
             set returnTarget(id) { returnTarget = id; }
             set returnTarget(id) { returnTarget = id; },
            pauseObserver: function() {
                if (layout && layout._ocObserver) layout._ocObserver.disconnect();
            },
            resumeObserver: function() {
                if (layout && layout[0] && layout._ocObserver) {
                    layout._ocObserver.observe(layout[0], {
                        subtree: true, attributes: true, attributeFilter: ['class']
                    });
                }
            }
         };
         };
     })();
     })();
Zeile 1.257: Zeile 1.338:
                 var $icon = $('<a class="book-nav-icon"></a>');
                 var $icon = $('<a class="book-nav-icon"></a>');
                 if (isBookRoot) {
                 if (isBookRoot) {
                     $icon.attr('href', '/');
                     var saved = sessionStorage.getItem('preprint-position');
                    if (saved) {
                        var pos = JSON.parse(saved);
                        $icon.attr('href', '/wiki/' + pos.article);
                    } else {
                        $icon.attr('href', '#');
                        $icon.addClass('book-nav-icon-disabled');
                    }
                 } else {
                 } else {
                     $icon.attr('href', '/wiki/' + book + (rootAnchor ? '#' + rootAnchor : ''));
                     $icon.attr('href', '/wiki/' + book + (rootAnchor ? '#' + rootAnchor : ''));
Zeile 1.272: Zeile 1.360:
                             var pos = JSON.parse(saved);
                             var pos = JSON.parse(saved);
                             window.location.href = '/wiki/' + pos.article;
                             window.location.href = '/wiki/' + pos.article;
                        } else {
                            window.location.href = '/';
                         }
                         }
                        // No action when disabled — no homepage fallback
                     });
                     });
                 } else {
                 } else {
Zeile 1.303: Zeile 1.390:
                 }
                 }
             }
             }
           
            console.log('Preprint Features: BookNav icon (root=' + isBookRoot + ')');
         }
         }


Zeile 1.370: Zeile 1.455:
              
              
             $landmark.before($link);
             $landmark.before($link);
             console.log('Preprint Features: Sidebar nav (root=' + isBookRoot + ')');
             if (mw.config.get('wgUserName')) {
                var style = document.createElement('style');
                style.textContent = '@media(max-width:790px){.book-nav-sidebar{display:none!important}}';
                document.head.appendChild(style);
            }
         }
         }


Zeile 1.512: Zeile 1.601:
                 // Mobile: root page IS the TOC, hide MW-generated one
                 // Mobile: root page IS the TOC, hide MW-generated one
                 $('.toc, #toc').hide();
                 $('.toc, #toc').hide();
                console.log('Preprint Features: TOC suppressed (bookRoot+Minerva)');
             } else if (isPreprintLayout && bookNavData.length && PAL.isMinerva()) {
             } else if (isPreprintLayout && bookNavData.length && PAL.isMinerva()) {
                 // Mobile book chapters: linear reading, no TOC
                 // Mobile book chapters: linear reading, no TOC
                 $('.toc, #toc').hide();
                 $('.toc, #toc').hide();
                console.log('Preprint Features: TOC suppressed (chapter+BookNav+Minerva)');
             }
             }
             // Desktop: TOC always visible (sticky sidebar navigation)
             // Desktop: TOC always visible (sticky sidebar navigation)
Zeile 1.561: Zeile 1.648:
             return;
             return;
         }
         }
       
               
        console.log('Preprint: PAL ready, building structure');
       
         // Build structure (Model)
         // Build structure (Model)
         Model.buildStructure();
         Model.buildStructure();
Zeile 1.571: Zeile 1.656:
         setTimeout(function() {
         setTimeout(function() {
             Model.applyProjection(initialMode);
             Model.applyProjection(initialMode);
            Model.pauseObserver();
             $('.preprint-layout').addClass('preprint-ready');
             $('.preprint-layout').addClass('preprint-ready');
            Model.resumeObserver();
             window.preprintReadyAt = performance.now();
             window.preprintReadyAt = performance.now();
         }, 50);
         }, 50);
Zeile 1.615: Zeile 1.702:
          
          
         PAL.onProjectionChange(function(event) {
         PAL.onProjectionChange(function(event) {
            console.log('Preprint: Projection change ' + event.from + ' -> ' + event.to);
              
              
             // Icon already hidden by onPreProjectionChange
             // Icon already hidden by onPreProjectionChange
Zeile 1.628: Zeile 1.714:
                     Features.calculateIconMetrics();
                     Features.calculateIconMetrics();
                     if (icon) icon.style.visibility = '';
                     if (icon) icon.style.visibility = '';
                    Model.positionOCElements();
                 }, 100);
                 }, 100);
             } else {
             } else {
Zeile 1.661: Zeile 1.748:
         });
         });
          
          
         mw.loader.load('/wiki/MediaWiki:Common.js/debug.js?action=raw&ctype=text/javascript');         
         // mw.loader.load('/wiki/MediaWiki:Common.js/debug.js?action=raw&ctype=text/javascript');         
        console.log('Preprint: Initialization complete (v7.17)');
     });
     });


})();
})();


/* === PREPRINT END === */


/* === PREPRINT END === */




/* Unified Consent System JavaScript v250911r1
/* === CONSENT START === */
/* Unified Consent System JavaScript v260224r1
  * Single file for both EN and DE versions
  * Single file for both EN and DE versions
  * Automatically detects language based on domain
  * Automatically detects language based on domain
Zeile 1.710: Zeile 1.797:
}
}


// Handle consent acquisition box - 90-day reminder for everyone
// Handle consent acquisition box - 90-day reminder for visitors (spec §8.9)
$(document).ready(function() {
$(document).ready(function() {
     var consentBox = document.getElementById('consent-acquisition-box');
     var consentBox = document.getElementById('consent-acquisition-box');
Zeile 1.732: Zeile 1.819:
         // ADD THIS LINE:
         // ADD THIS LINE:
         localStorage.setItem('consent-acquisition-dismissed-until', Date.now() + (90 * 24 * 60 * 60 * 1000));
         localStorage.setItem('consent-acquisition-dismissed-until', Date.now() + (90 * 24 * 60 * 60 * 1000));
         var targetPage = getCurrentLanguage() === 'de' ?  
         if (mw.config.get('wgUserName')) {
            '/wiki/Transformal_GmbH:Einstellungen' :  
            window.location.href = '/wiki/Special:Preferences#mw-prefsection-legal';
            '/wiki/Transformal_GmbH:Settings';
        } else {
        window.location.href = targetPage;
            var targetPage = getCurrentLanguage() === 'de' ?  
                '/wiki/Transformal_GmbH:Einstellungen' :  
                '/wiki/Transformal_GmbH:Settings';
            window.location.href = targetPage;
        }
     });
     });
});
});
Zeile 1.833: Zeile 1.924:
     }
     }
}
}
/* === CONSENT END === */
/* === CONDITIONAL START === */


/* Template 'ConditionalContent' - v250925r8 */
/* Template 'ConditionalContent' - v250925r8 */
Zeile 1.893: Zeile 1.988:
     }
     }
});
});
/* === CONDITIONAL END === */