MediaWiki:Common.js: відмінності між версіями

нема опису редагування
Немає опису редагування
Немає опису редагування
Рядок 42: Рядок 42:
// ============================================================
// ============================================================
// 2. L-BOX NAVIGATION
// 2. L-BOX NAVIGATION
// document.getElementById — коректно обробляє кирилицю
// ============================================================
// ============================================================
$(function () {
$(function () {
Рядок 49: Рядок 48:


     var $items = $lbox.find('.l-box-item');
     var $items = $lbox.find('.l-box-item');
    var HEADER_OFFSET = 78;
    var isAnimating = false;


     function buildSectionMap() {
    // Знаходить елемент-заголовок для якоря (міряємо ЗАВЖДИ в момент виклику)
         var map = [];
     function getTargetEl(target) {
         $items.each(function () {
         if (target === 'top') return null;
            var target = $(this).data('target');
         var el = document.getElementById(target);
            if (target === 'top') {
        if (!el) return null;
                map.push({ $item: $(this), top: 0 });
        var $el = $(el);
        var $heading = $el.closest('h1, h2, h3, h4');
        return $heading.length ? $heading[0] : el;
    }
 
    function getTargetTop(target) {
        if (target === 'top') return 0;
        var el = getTargetEl(target);
        if (!el) return null;
        // getBoundingClientRect + поточний скрол — актуально на момент виклику
        return el.getBoundingClientRect().top + window.pageYOffset - HEADER_OFFSET;
    }
 
    function scrollToTarget(target) {
        var top = getTargetTop(target);
        if (top === null) return;
 
        isAnimating = true;
        $('html, body').stop(true, false).animate({ scrollTop: Math.max(0, top) }, 280, function () {
            // Перевірка після анімації: якщо layout зсунувся — доводимо
            var corrected = getTargetTop(target);
            if (corrected !== null && Math.abs(corrected - window.pageYOffset) > 4) {
                $('html, body').stop(true, false).animate(
                    { scrollTop: Math.max(0, corrected) }, 120,
                    function () { isAnimating = false; }
                );
             } else {
             } else {
                 var el = document.getElementById(target);
                 isAnimating = false;
                if (el) {
                    var $el = $(el);
                    var $heading = $el.closest('h2, h3, h4').length
                        ? $el.closest('h2, h3, h4') : $el;
                    map.push({ $item: $(this), top: $heading.offset().top });
                }
             }
             }
         });
         });
        map.sort(function (a, b) { return a.top - b.top; });
        return map;
     }
     }


     function updateActive(map) {
     function updateActive() {
         var scrollY = $(window).scrollTop() + 120;
        if (isAnimating) return;            // не перебиваємо підсвітку під час переходу
         var scrollY = window.pageYOffset + 120;
         var current = null;
         var current = null;
         for (var i = 0; i < map.length; i++) {
 
             if (map[i].top <= scrollY) current = map[i].$item;
         $items.each(function () {
         }
            var target = $(this).data('target');
            var top = (target === 'top') ? 0 : getTargetTop(target);
             if (top !== null && top - HEADER_OFFSET <= scrollY) current = $(this);
         });
 
         $items.removeClass('active');
         $items.removeClass('active');
         if (current) current.addClass('active');
         if (current) current.addClass('active');
Рядок 85: Рядок 108:
         $(this).addClass('active');
         $(this).addClass('active');


        // If games tab is active — switch to profile first, then scroll
         var $profileTab = $('.player-tab[data-tab="profile"], .player-tab[data-tab="info"]');
         var $profileTab = $('.player-tab[data-tab="profile"], .player-tab[data-tab="info"]');
         var $gamesTab  = $('.player-tab[data-tab="games"]');
         var $gamesTab  = $('.player-tab[data-tab="games"]');
        var gamesActive = $gamesTab.length && $gamesTab.hasClass('active');
        function doScroll() {
            if (target === 'top') {
                $('html, body').animate({ scrollTop: 0 }, 280);
            } else {
                var el = document.getElementById(target);
                if (el) {
                    var $el = $(el);
                    var $heading = $el.closest('h2, h3, h4').length
                        ? $el.closest('h2, h3, h4') : $el;
                    $('html, body').animate({ scrollTop: $heading.offset().top - 78 }, 280);
                }
            }
        }


         if (gamesActive) {
         if ($gamesTab.length && $gamesTab.hasClass('active')) {
            // Click the profile tab to switch
             $profileTab.trigger('click');
             $profileTab.trigger('click');
            // Wait for tab switch + DOM
             setTimeout(function () { scrollToTarget(target); }, 150);
             setTimeout(doScroll, 120);
         } else {
         } else {
             doScroll();
             scrollToTarget(target);
         }
         }
    });
    var sectionMap = buildSectionMap();
    $(document).on('mcc:content-loaded', function () {
        sectionMap = buildSectionMap();
        updateActive(sectionMap);
     });
     });


Рядок 125: Рядок 123:
         if (!ticking) {
         if (!ticking) {
             window.requestAnimationFrame(function () {
             window.requestAnimationFrame(function () {
                 updateActive(sectionMap);
                 updateActive();
                 ticking = false;
                 ticking = false;
             });
             });
Рядок 132: Рядок 130:
     });
     });


     $(window).on('resize', function () {
     $(window).on('resize', updateActive);
        sectionMap = buildSectionMap();
    $(document).on('mcc:content-loaded', updateActive);
         updateActive(sectionMap);
 
     });
    // Перерахунок після довантаження картинок і шрифтів
    $(window).on('load', updateActive);
    if (document.fonts && document.fonts.ready) {
         document.fonts.ready.then(updateActive);
     }


     setTimeout(function () {
     updateActive();
        sectionMap = buildSectionMap();
        updateActive(sectionMap);
    }, 200);
});
});