MediaWiki:Common.js: Difference between revisions

From CoraTO Wiki - Official Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
// Script to ensure the sidebar remains always visible
// MainPage2 interactions. Designed for MediaWiki site usage.
// Add this script to MediaWiki:Common.js or include in HTML
(function(){
  'use strict';


(function() {
  // Simple tab controller (inspired by GuardianGuide.html)
     'use strict';
  window.showTab = function(tabId, el){
      
     var contents = document.querySelectorAll('.tab-content');
     // Function to force sidebar visibility
     for (var i=0;i<contents.length;i++){ contents[i].classList.remove('active'); }
     function forceSidebarVisibility() {
     var tabs = document.querySelectorAll('.nav-tab');
        const sidebar = document.getElementById('mw-panel');
     for (var j=0;j<tabs.length;j++){ tabs[j].classList.remove('active'); }
        if (sidebar) {
    var target = document.getElementById(tabId);
            sidebar.style.display = 'block';
    if (target) target.classList.add('active');
            sidebar.style.visibility = 'visible';
    if (el) el.classList.add('active');
            sidebar.style.opacity = '1';
  };
            sidebar.style.position = 'fixed';
 
            sidebar.style.left = '0';
  // MediaWiki-safe tab click handler using event delegation
            sidebar.style.top = '0';
  function onTabClick(e) {
            sidebar.style.width = '180px';
    var tab = e.target.closest('.nav-tab[data-tab]');
            sidebar.style.height = '100vh';
    if (!tab) return;
            sidebar.style.zIndex = '100';
    e.preventDefault();
        }
    var targetId = tab.getAttribute('data-tab');
    if (targetId) {
      showTab(targetId, tab);
    }
  }
  document.addEventListener('click', onTabClick, false);
 
  // Handle special navigation clicks for tabs (like in Hologramsie)
  function onSpecialTabNav(e) {
    var trigger = e.target.closest('[data-tab-trigger]');
    if (!trigger) return;
    e.preventDefault();
    var tabData = trigger.getAttribute('data-tab-trigger');
    var buttonId = trigger.getAttribute('data-tab-button');
 
    // Support anchors via href="#section" when data-scroll-to is not provided
    var href = trigger.getAttribute('href');
    var scrollToAttr = trigger.getAttribute('data-scroll-to');
    var scrollTargetSelector = null;
    if (scrollToAttr && scrollToAttr.trim()) {
      scrollTargetSelector = '#' + scrollToAttr.replace(/^#/, '');
    } else if (href && href.charAt(0) === '#') {
      scrollTargetSelector = href; // already a selector
     }
     }
      
      
     // Function to force back-to-top button visibility and functionality
     if (tabData && buttonId) {
    function forceBackToTopButton() {
      var targetButton = document.getElementById(buttonId);
        const backToTopBtn = document.getElementById('back-to-top-btn');
      if (targetButton) {
        if (backToTopBtn) {
        showTab(tabData, targetButton);
            // Force visibility styles
        // Scroll to anchor if specified (from data-scroll-to or href)
            backToTopBtn.style.position = 'fixed';
        if (scrollTargetSelector) {
            backToTopBtn.style.bottom = '20px';
          var element = document.querySelector(scrollTargetSelector);
            backToTopBtn.style.right = '20px';
          if (element) {
            backToTopBtn.style.zIndex = '99999';
            setTimeout(function() {
            backToTopBtn.style.display = 'block';
              element.scrollIntoView({behavior: 'smooth'});
            backToTopBtn.style.visibility = 'visible';
            }, 100);
            backToTopBtn.style.opacity = '1';
          }
            backToTopBtn.style.pointerEvents = 'auto';
           
            // Ensure the link inside is also visible
            const link = backToTopBtn.querySelector('a');
            if (link) {
                link.style.display = 'inline-block';
                link.style.visibility = 'visible';
                link.style.opacity = '1';
                link.style.pointerEvents = 'auto';
               
                // Add click event if not already present
                if (!link.hasAttribute('data-click-added')) {
                    link.addEventListener('click', function(e) {
                        e.preventDefault();
                        window.scrollTo({
                            top: 0,
                            behavior: 'smooth'
                        });
                    });
                    link.setAttribute('data-click-added', 'true');
                }
            }
         }
         }
      }
     }
     }
   
  }
    // Execute when DOM is loaded
  document.addEventListener('click', onSpecialTabNav, false);
     if (document.readyState === 'loading') {
 
        document.addEventListener('DOMContentLoaded', function() {
  // Back to Top smooth scroll
            forceSidebarVisibility();
  function onBackToTop(e){
            forceBackToTopButton();
    var trigger = e.target.closest('.back-to-top');
        });
     if (!trigger) return;
     } else {
    e.preventDefault();
        forceSidebarVisibility();
    window.scrollTo({ top: 0, behavior: 'smooth' });
         forceBackToTopButton();
  }
  document.addEventListener('click', onBackToTop, false);
 
  // Card click-throughs using data-link to wiki pages or in-page anchors
  function onCardClick(e){
    var card = e.target.closest('.card[data-link], .destaque-card[data-link]');
    if (!card) return;
    var link = card.getAttribute('data-link');
    if (!link) return;
 
    // In-page anchor navigation: data-link="#section-id"
     if (link.charAt(0) === '#') {
      e.preventDefault();
      var anchorEl = document.querySelector(link);
      if (anchorEl) {
         anchorEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }
      return;
     }
     }
   
 
     // Execute when page is completely loaded
     // Absolute external URL
     window.addEventListener('load', function() {
     if (/^https?:\/\//i.test(link)) {
        forceSidebarVisibility();
      window.location.href = link;
        forceBackToTopButton();
      return;
    });
   
    // Observe DOM changes to react to dynamic modifications
    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type === 'attributes' && mutation.target.id === 'mw-panel') {
                forceSidebarVisibility();
            }
            if (mutation.type === 'attributes' && mutation.target.id === 'back-to-top-btn') {
                forceBackToTopButton();
            }
        });
    });
   
    // Start observation when element exists
    function startObserving() {
        const sidebar = document.getElementById('mw-panel');
        if (sidebar) {
            observer.observe(sidebar, {
                attributes: true,
                attributeFilter: ['style', 'class']
            });
        } else {
            // Try again after a small delay
            setTimeout(startObserving, 100);
        }
       
        const backToTopBtn = document.getElementById('back-to-top-btn');
        if (backToTopBtn) {
            observer.observe(backToTopBtn, {
                attributes: true,
                attributeFilter: ['style', 'class']
            });
        }
     }
     }
   
 
     startObserving();
     // Navigate to the MediaWiki page (prefer mw.util if available)
      
     var targetUrl = (window.mw && mw.util && typeof mw.util.getUrl === 'function')
    // Execute functions periodically as backup
      ? mw.util.getUrl(link)
    setInterval(function() {
      : ('index.php?title=' + encodeURIComponent(link));
        forceSidebarVisibility();
     window.location.href = targetUrl;
        forceBackToTopButton();
  }
     }, 1000);
  document.addEventListener('click', onCardClick, false);
   
 
    // Execute when window is resized
  // Helper: determine if a node is inside an excluded container
    window.addEventListener('resize', function() {
  function isInExcludedContext(node) {
        forceSidebarVisibility();
    if (!node || !node.parentElement) return false;
        forceBackToTopButton();
    var p = node.parentElement.closest('script, style, textarea, input, select, option, .ve-ui-surface, .mw-editform, .CodeMirror, .cm-editor, .ace_editor');
     });
     return !!p;
   
  }
     // Execute when page visibility changes
 
     document.addEventListener('visibilitychange', function() {
  // Safely process MediaWiki-like internal link markup [[Title]] -> <a href="...">Title</a>
        if (!document.hidden) {
  function processWikiLinks() {
            forceSidebarVisibility();
     // Skip if the page was already parsed by MediaWiki (no raw brackets found)
            forceBackToTopButton();
     if (document.body && document.body.textContent.indexOf('[[') === -1) return;
        }
 
     });
    var walker = document.createTreeWalker(
      
      document.body,
     // Execute when page is scrolled (for back-to-top button)
      NodeFilter.SHOW_TEXT,
    window.addEventListener('scroll', forceBackToTopButton);
      null,
   
      false
    // Execute after MediaWiki scripts load
    );
    if (typeof mw !== 'undefined' && mw.loader) {
 
        mw.loader.using(['mediawiki.util'], function() {
     var textNodes = [];
            forceSidebarVisibility();
     var node;
            forceBackToTopButton();
     while ((node = walker.nextNode())) {
        });
      var value = node.nodeValue;
      if (!value) continue;
      if (value.indexOf('[[') === -1) continue;
      if (isInExcludedContext(node)) continue;
      textNodes.push(node);
     }
     }
   
})();


/* ========================================
    var linkRe = /\[\[([^\|\]]+)(?:\|([^\]]+))?\]\]/g;
  CARDS NAVIGATION SCRIPT
 
  Makes highlight cards clickable
    textNodes.forEach(function(textNode) {
  ======================================== */
      var src = textNode.nodeValue;
      if (!linkRe.test(src)) return; // quick check
      linkRe.lastIndex = 0; // reset stateful regex
 
      var parent = textNode.parentNode;
      var frag = document.createDocumentFragment();
      var last = 0; var m;
 
      while ((m = linkRe.exec(src)) !== null) {
        // text before match
        if (m.index > last) frag.appendChild(document.createTextNode(src.slice(last, m.index)));
 
        var rawTitle = (m[1] || '').trim();
        var display = (m[2] != null ? m[2] : rawTitle).trim();


(function() {
         // Skip File: or Image: links - keep original text intact
    'use strict';
         if (/^(File:|Image:)/i.test(rawTitle)) {
   
          frag.appendChild(document.createTextNode(m[0]));
    // Function to make cards clickable
    function makeCardsClickable() {
         // Select all highlight cards
        const cards = document.querySelectorAll('.destaque-card[data-link]');
          
        cards.forEach(function(card) {
            // Add pointer cursor
            card.style.cursor = 'pointer';
           
            // Add click event
            card.addEventListener('click', function() {
                const linkTarget = this.getAttribute('data-link');
               
                if (linkTarget) {
                    // Check if it's an anchor link (starts with #)
                    if (linkTarget.startsWith('#')) {
                        // Navigate to section within the same page
                        const targetElement = document.querySelector(linkTarget);
                        if (targetElement) {
                            targetElement.scrollIntoView({
                                behavior: 'smooth',
                                block: 'start'
                            });
                        } else {
                            // Fallback: use window.location.hash
                            window.location.hash = linkTarget;
                        }
                    } else {
                        // Build MediaWiki page URL for external links
                        const pageUrl = linkTarget.replace(/\s+/g, '_');
                       
                        // Navigate to page
                        if (typeof mw !== 'undefined' && mw.config) {
                            // In MediaWiki - use MediaWiki API
                            const baseUrl = mw.config.get('wgServer') + mw.config.get('wgScriptPath');
                            window.location.href = baseUrl + '/index.php/' + encodeURIComponent(pageUrl);
                        } else {
                            // Fallback - assume standard MediaWiki structure
                            window.location.href = '/wiki/' + encodeURIComponent(pageUrl);
                        }
                    }
                }
            });
           
            // Add visual hover effect
            card.addEventListener('mouseenter', function() {
                this.style.transform = 'translateY(-8px)';
                this.style.boxShadow = '0 12px 40px rgba(255, 107, 157, 0.3)';
            });
           
            card.addEventListener('mouseleave', function() {
                this.style.transform = 'translateY(0)';
                this.style.boxShadow = '0 8px 32px rgba(255, 107, 157, 0.2)';
            });
        });
       
        console.log('Highlight cards made clickable:', cards.length + ' cards processed');
    }
   
    // Function to initialize when DOM is ready
    function initializeCards() {
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', makeCardsClickable);
         } else {
         } else {
             makeCardsClickable();
          // Remove leading colon if present
          if (rawTitle.charAt(0) === ':') rawTitle = rawTitle.slice(1);
          var href = (window.mw && mw.util && typeof mw.util.getUrl === 'function')
            ? mw.util.getUrl(rawTitle)
             : ('index.php?title=' + encodeURIComponent(rawTitle));
          var a = document.createElement('a');
          a.className = 'mw-link-internal';
          a.setAttribute('href', href);
          a.appendChild(document.createTextNode(display)); // avoid HTML injection
          frag.appendChild(a);
         }
         }
    }
 
   
         last = linkRe.lastIndex;
    // Observe DOM changes for dynamically added cards
      }
    function observeChanges() {
 
         if (typeof MutationObserver !== 'undefined') {
      // trailing text
            const observer = new MutationObserver(function(mutations) {
      if (last < src.length) frag.appendChild(document.createTextNode(src.slice(last)));
                let shouldReinitialize = false;
 
               
      // Replace the original text node safely
                mutations.forEach(function(mutation) {
      parent.insertBefore(frag, textNode);
                    if (mutation.type === 'childList') {
      parent.removeChild(textNode);
                        // Check if new cards were added
                        mutation.addedNodes.forEach(function(node) {
                            if (node.nodeType === 1) { // Element node
                                if (node.classList && node.classList.contains('destaque-card') ||
                                    node.querySelector && node.querySelector('.destaque-card')) {
                                    shouldReinitialize = true;
                                }
                            }
                        });
                    }
                });
               
                if (shouldReinitialize) {
                    setTimeout(makeCardsClickable, 100);
                }
            });
           
            // Observe changes in body
            observer.observe(document.body, {
                childList: true,
                subtree: true
            });
        }
    }
   
    // Initialize the script
    initializeCards();
   
    // Start observing changes
    observeChanges();
   
    // Reinitialize after complete page load
    window.addEventListener('load', function() {
        setTimeout(makeCardsClickable, 500);
     });
     });
   
  }
    // Export function for manual use if needed
    window.initializeHighlightCards = makeCardsClickable;
   
})();
 
/* ========================================
  RESPONSIVE TABS MENU SCRIPT
  Provides compact mobile-friendly navigation for MediaWiki tabs
  ======================================== */


(function() {
  // Process wiki links when DOM is ready
    'use strict';
  if (document.readyState === 'loading') {
   
    document.addEventListener('DOMContentLoaded', processWikiLinks);
    // Wait for DOM to be ready
  } else {
    if (document.readyState === 'loading') {
    processWikiLinks();
        document.addEventListener('DOMContentLoaded', initResponsiveTabs);
  }
    } else {
  // Mobile hamburger menu for sidebar
        initResponsiveTabs();
  function createHamburgerMenu() {
     }
    // Only create if we're in MediaWiki Vector Legacy and on mobile
     if (!document.body.classList.contains('skin-vector-legacy')) return;
      
      
     function initResponsiveTabs() {
     var panel = document.getElementById('mw-panel');
        // Create toggle buttons for each tab container
    if (!panel) return;
        createToggleButtons();
       
        // Handle window resize
        window.addEventListener('resize', handleResize);
       
        // Initial setup
        handleResize();
    }
      
      
     function createToggleButtons() {
     // Create hamburger button
        const tabContainers = [
    var hamburger = document.createElement('button');
            { selector: '#p-namespaces ul', label: 'Namespaces ▼', id: 'namespace-dropdown' },
    hamburger.className = 'mobile-hamburger-menu';
            { selector: '#p-views ul', label: 'Views ▼', id: 'views-dropdown' },
    hamburger.setAttribute('aria-label', 'Toggle navigation menu');
            { selector: '#p-cactions ul', label: 'Actions ▼', id: 'actions-dropdown' },
    hamburger.innerHTML = '<span></span><span></span><span></span>';
            { selector: '#p-personal ul', label: 'Personal ▼', id: 'personal-dropdown' }
        ];
       
        tabContainers.forEach(container => {
            const element = document.querySelector(container.selector);
            if (element && !element.previousElementSibling?.classList.contains('mw-tabs-toggle')) {
                createToggleButton(element, container.label, container.id);
            }
        });
    }
      
      
     function createToggleButton(tabContainer, label, id) {
     // Insert hamburger button at the top of the page
        const toggle = document.createElement('button');
    var content = document.getElementById('content') || document.querySelector('.mw-body');
        toggle.className = 'mw-tabs-toggle';
    if (content) {
        toggle.textContent = label;
      content.parentNode.insertBefore(hamburger, content);
        toggle.setAttribute('aria-expanded', 'false');
        toggle.setAttribute('aria-controls', id || 'tabs-menu');
        toggle.setAttribute('data-target', id);
       
        // Insert toggle before the tab container
        tabContainer.parentNode.insertBefore(toggle, tabContainer);
       
        // Add click event listener
        toggle.addEventListener('click', function(e) {
            e.preventDefault();
            toggleMenu(toggle, tabContainer);
        });
       
        // Close menu when clicking outside
        document.addEventListener('click', function(e) {
            if (!toggle.contains(e.target) && !tabContainer.contains(e.target)) {
                closeMenu(toggle, tabContainer);
            }
        });
     }
     }
      
      
     function toggleMenu(toggle, tabContainer) {
     // Toggle sidebar function
        const isOpen = tabContainer.classList.contains('show');
    function toggleSidebar() {
       
      panel.classList.toggle('mobile-open');
        if (isOpen) {
      hamburger.classList.toggle('active');
            closeMenu(toggle, tabContainer);
      document.body.classList.toggle('sidebar-open');
        } else {
            openMenu(toggle, tabContainer);
        }
     }
     }
      
      
     function openMenu(toggle, tabContainer) {
     // Click handler for hamburger
        // Close other open menus first
    hamburger.addEventListener('click', function(e) {
        document.querySelectorAll('#p-namespaces ul.show, #p-views ul.show, #p-cactions ul.show, #p-personal ul.show')
      e.preventDefault();
            .forEach(menu => {
      e.stopPropagation();
                if (menu !== tabContainer) {
      toggleSidebar();
                    menu.classList.remove('show');
    });
                    const relatedToggle = menu.previousElementSibling;
                    if (relatedToggle && relatedToggle.classList.contains('mw-tabs-toggle')) {
                        relatedToggle.setAttribute('aria-expanded', 'false');
                        const originalText = relatedToggle.textContent.replace(' ▲', ' ▼');
                        relatedToggle.textContent = originalText;
                    }
                }
            });
       
        tabContainer.classList.add('show');
        toggle.setAttribute('aria-expanded', 'true');
        const newText = toggle.textContent.replace(' ▼', ' ▲');
        toggle.textContent = newText;
    }
      
      
     function closeMenu(toggle, tabContainer) {
     // Close sidebar when clicking outside
        tabContainer.classList.remove('show');
    document.addEventListener('click', function(e) {
         toggle.setAttribute('aria-expanded', 'false');
      if (panel.classList.contains('mobile-open') &&
         const originalText = toggle.textContent.replace(' ▲', ' ▼');
          !panel.contains(e.target) &&
         toggle.textContent = originalText;
          !hamburger.contains(e.target)) {
     }
         panel.classList.remove('mobile-open');
         hamburger.classList.remove('active');
         document.body.classList.remove('sidebar-open');
      }
     });
      
      
     function handleResize() {
     // Close sidebar on escape key
        const isSmallScreen = window.innerWidth <= 1366;
       
        // Show/hide toggle buttons based on screen size
        document.querySelectorAll('.mw-tabs-toggle').forEach(toggle => {
            toggle.style.display = isSmallScreen ? 'inline-block' : 'none';
        });
       
        // Reset menu state on larger screens
        if (!isSmallScreen) {
            document.querySelectorAll('#p-namespaces ul, #p-views ul, #p-cactions ul, #p-personal ul').forEach(menu => {
                menu.classList.remove('show');
                menu.style.display = '';
            });
           
            document.querySelectorAll('.mw-tabs-toggle').forEach(toggle => {
                toggle.setAttribute('aria-expanded', 'false');
                const originalText = toggle.textContent.replace(' ▲', ' ▼');
                toggle.textContent = originalText;
            });
        }
    }
   
    // Handle dropdown menus for overflow tabs
    function initDropdownMenus() {
        const dropdowns = document.querySelectorAll('.mw-tabs-dropdown');
       
        dropdowns.forEach(dropdown => {
            const trigger = dropdown.querySelector('.mw-tabs-dropdown-trigger');
            if (trigger) {
                trigger.addEventListener('click', function(e) {
                    e.preventDefault();
                    dropdown.classList.toggle('active');
                });
            }
        });
       
        // Close dropdowns when clicking outside
        document.addEventListener('click', function(e) {
            dropdowns.forEach(dropdown => {
                if (!dropdown.contains(e.target)) {
                    dropdown.classList.remove('active');
                }
            });
        });
    }
   
    // Initialize dropdown functionality
    initDropdownMenus();
   
    // Add keyboard navigation support
     document.addEventListener('keydown', function(e) {
     document.addEventListener('keydown', function(e) {
        if (e.key === 'Escape') {
      if (e.key === 'Escape' && panel.classList.contains('mobile-open')) {
            // Close all open menus on Escape
        panel.classList.remove('mobile-open');
            document.querySelectorAll('#p-namespaces ul.show, #p-views ul.show, #p-cactions ul.show, #p-personal ul.show').forEach(menu => {
        hamburger.classList.remove('active');
                menu.classList.remove('show');
        document.body.classList.remove('sidebar-open');
                const toggle = menu.previousElementSibling;
      }
                if (toggle && toggle.classList.contains('mw-tabs-toggle')) {
                    toggle.setAttribute('aria-expanded', 'false');
                    const originalText = toggle.textContent.replace(' ▲', ' ▼');
                    toggle.textContent = originalText;
                }
            });
           
            // Close dropdowns
            document.querySelectorAll('.mw-tabs-dropdown.active').forEach(dropdown => {
                dropdown.classList.remove('active');
            });
        }
     });
     });
      
  }
 
  // Initialize hamburger menu when DOM is ready
  if (document.readyState === 'loading') {
     document.addEventListener('DOMContentLoaded', createHamburgerMenu);
  } else {
    createHamburgerMenu();
  }
 
})();
})();

Revision as of 05:58, 11 August 2025

// MainPage2 interactions. Designed for MediaWiki site usage.
(function(){
  'use strict';

  // Simple tab controller (inspired by GuardianGuide.html)
  window.showTab = function(tabId, el){
    var contents = document.querySelectorAll('.tab-content');
    for (var i=0;i<contents.length;i++){ contents[i].classList.remove('active'); }
    var tabs = document.querySelectorAll('.nav-tab');
    for (var j=0;j<tabs.length;j++){ tabs[j].classList.remove('active'); }
    var target = document.getElementById(tabId);
    if (target) target.classList.add('active');
    if (el) el.classList.add('active');
  };

  // MediaWiki-safe tab click handler using event delegation
  function onTabClick(e) {
    var tab = e.target.closest('.nav-tab[data-tab]');
    if (!tab) return;
    e.preventDefault();
    var targetId = tab.getAttribute('data-tab');
    if (targetId) {
      showTab(targetId, tab);
    }
  }
  document.addEventListener('click', onTabClick, false);

  // Handle special navigation clicks for tabs (like in Hologramsie)
  function onSpecialTabNav(e) {
    var trigger = e.target.closest('[data-tab-trigger]');
    if (!trigger) return;
    e.preventDefault();
    var tabData = trigger.getAttribute('data-tab-trigger');
    var buttonId = trigger.getAttribute('data-tab-button');

    // Support anchors via href="#section" when data-scroll-to is not provided
    var href = trigger.getAttribute('href');
    var scrollToAttr = trigger.getAttribute('data-scroll-to');
    var scrollTargetSelector = null;
    if (scrollToAttr && scrollToAttr.trim()) {
      scrollTargetSelector = '#' + scrollToAttr.replace(/^#/, '');
    } else if (href && href.charAt(0) === '#') {
      scrollTargetSelector = href; // already a selector
    }
    
    if (tabData && buttonId) {
      var targetButton = document.getElementById(buttonId);
      if (targetButton) {
        showTab(tabData, targetButton);
        // Scroll to anchor if specified (from data-scroll-to or href)
        if (scrollTargetSelector) {
          var element = document.querySelector(scrollTargetSelector);
          if (element) {
            setTimeout(function() {
              element.scrollIntoView({behavior: 'smooth'});
            }, 100);
          }
        }
      }
    }
  }
  document.addEventListener('click', onSpecialTabNav, false);

  // Back to Top smooth scroll
  function onBackToTop(e){
    var trigger = e.target.closest('.back-to-top');
    if (!trigger) return;
    e.preventDefault();
    window.scrollTo({ top: 0, behavior: 'smooth' });
  }
  document.addEventListener('click', onBackToTop, false);

  // Card click-throughs using data-link to wiki pages or in-page anchors
  function onCardClick(e){
    var card = e.target.closest('.card[data-link], .destaque-card[data-link]');
    if (!card) return;
    var link = card.getAttribute('data-link');
    if (!link) return;

    // In-page anchor navigation: data-link="#section-id"
    if (link.charAt(0) === '#') {
      e.preventDefault();
      var anchorEl = document.querySelector(link);
      if (anchorEl) {
        anchorEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }
      return;
    }

    // Absolute external URL
    if (/^https?:\/\//i.test(link)) {
      window.location.href = link;
      return;
    }

    // Navigate to the MediaWiki page (prefer mw.util if available)
    var targetUrl = (window.mw && mw.util && typeof mw.util.getUrl === 'function')
      ? mw.util.getUrl(link)
      : ('index.php?title=' + encodeURIComponent(link));
    window.location.href = targetUrl;
  }
  document.addEventListener('click', onCardClick, false);

  // Helper: determine if a node is inside an excluded container
  function isInExcludedContext(node) {
    if (!node || !node.parentElement) return false;
    var p = node.parentElement.closest('script, style, textarea, input, select, option, .ve-ui-surface, .mw-editform, .CodeMirror, .cm-editor, .ace_editor');
    return !!p;
  }

  // Safely process MediaWiki-like internal link markup [[Title]] -> <a href="...">Title</a>
  function processWikiLinks() {
    // Skip if the page was already parsed by MediaWiki (no raw brackets found)
    if (document.body && document.body.textContent.indexOf('[[') === -1) return;

    var walker = document.createTreeWalker(
      document.body,
      NodeFilter.SHOW_TEXT,
      null,
      false
    );

    var textNodes = [];
    var node;
    while ((node = walker.nextNode())) {
      var value = node.nodeValue;
      if (!value) continue;
      if (value.indexOf('[[') === -1) continue;
      if (isInExcludedContext(node)) continue;
      textNodes.push(node);
    }

    var linkRe = /\[\[([^\|\]]+)(?:\|([^\]]+))?\]\]/g;

    textNodes.forEach(function(textNode) {
      var src = textNode.nodeValue;
      if (!linkRe.test(src)) return; // quick check
      linkRe.lastIndex = 0; // reset stateful regex

      var parent = textNode.parentNode;
      var frag = document.createDocumentFragment();
      var last = 0; var m;

      while ((m = linkRe.exec(src)) !== null) {
        // text before match
        if (m.index > last) frag.appendChild(document.createTextNode(src.slice(last, m.index)));

        var rawTitle = (m[1] || '').trim();
        var display = (m[2] != null ? m[2] : rawTitle).trim();

        // Skip File: or Image: links - keep original text intact
        if (/^(File:|Image:)/i.test(rawTitle)) {
          frag.appendChild(document.createTextNode(m[0]));
        } else {
          // Remove leading colon if present
          if (rawTitle.charAt(0) === ':') rawTitle = rawTitle.slice(1);
          var href = (window.mw && mw.util && typeof mw.util.getUrl === 'function')
            ? mw.util.getUrl(rawTitle)
            : ('index.php?title=' + encodeURIComponent(rawTitle));
          var a = document.createElement('a');
          a.className = 'mw-link-internal';
          a.setAttribute('href', href);
          a.appendChild(document.createTextNode(display)); // avoid HTML injection
          frag.appendChild(a);
        }

        last = linkRe.lastIndex;
      }

      // trailing text
      if (last < src.length) frag.appendChild(document.createTextNode(src.slice(last)));

      // Replace the original text node safely
      parent.insertBefore(frag, textNode);
      parent.removeChild(textNode);
    });
  }

  // Process wiki links when DOM is ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', processWikiLinks);
  } else {
    processWikiLinks();
  }
  // Mobile hamburger menu for sidebar
  function createHamburgerMenu() {
    // Only create if we're in MediaWiki Vector Legacy and on mobile
    if (!document.body.classList.contains('skin-vector-legacy')) return;
    
    var panel = document.getElementById('mw-panel');
    if (!panel) return;
    
    // Create hamburger button
    var hamburger = document.createElement('button');
    hamburger.className = 'mobile-hamburger-menu';
    hamburger.setAttribute('aria-label', 'Toggle navigation menu');
    hamburger.innerHTML = '<span></span><span></span><span></span>';
    
    // Insert hamburger button at the top of the page
    var content = document.getElementById('content') || document.querySelector('.mw-body');
    if (content) {
      content.parentNode.insertBefore(hamburger, content);
    }
    
    // Toggle sidebar function
    function toggleSidebar() {
      panel.classList.toggle('mobile-open');
      hamburger.classList.toggle('active');
      document.body.classList.toggle('sidebar-open');
    }
    
    // Click handler for hamburger
    hamburger.addEventListener('click', function(e) {
      e.preventDefault();
      e.stopPropagation();
      toggleSidebar();
    });
    
    // Close sidebar when clicking outside
    document.addEventListener('click', function(e) {
      if (panel.classList.contains('mobile-open') && 
          !panel.contains(e.target) && 
          !hamburger.contains(e.target)) {
        panel.classList.remove('mobile-open');
        hamburger.classList.remove('active');
        document.body.classList.remove('sidebar-open');
      }
    });
    
    // Close sidebar on escape key
    document.addEventListener('keydown', function(e) {
      if (e.key === 'Escape' && panel.classList.contains('mobile-open')) {
        panel.classList.remove('mobile-open');
        hamburger.classList.remove('active');
        document.body.classList.remove('sidebar-open');
      }
    });
  }
  
  // Initialize hamburger menu when DOM is ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', createHamburgerMenu);
  } else {
    createHamburgerMenu();
  }

})();