Jump to content
Go to Vaniquotes | Go to Vanipedia | Go to Vanimedia


Vanisource - the complete essence of Vedic knowledge


MediaWiki:Common.js

From Vanisource
Revision as of 11:50, 16 September 2026 by Kashya (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* Any JavaScript here will be loaded for all users on every page load. */

if (mw.config.get('wgPageName' ) === 'Krishna_says_in_Bhagavad-gita') { 
  /* switch tooltip texts from content-div to label-div */
  const v_labels = Array.from(document.getElementsByClassName("tabs-label"));
  const v_content = Array.from(document.getElementsByClassName("tabs-content"));
  for (var i = 0; i < v_labels.length; i++) {
    v_labels[i].title = v_content[i].title;
    v_content[i].title = "";
  }
  /* adjust wikitables */
  var arr = Array.from(document.getElementsByClassName("wikitable"));
  for (var t = 0; t < arr.length; t++) {
    /* insert THEAD in wikitable */
    var thead = document.createElement("thead");
    thead.style.display = "block";
    var wtbl = arr[t];
    wtbl.insertBefore(thead, wtbl.firstChild);
    /* move first row of TBODY to THEAD */
    thead.appendChild(wtbl.rows[0]);
    /* make TBODY scrollable */
    var tbody = wtbl.tBodies[0];
    tbody.style.display = "block";
    tbody.style.overflowY = "auto";
    tbody.style.maxHeight = "500px";    
    for (var r = 0; r < wtbl.rows.length; r++) {
      var row = wtbl.rows[r];
      /* adjust column widths and hide from-until columns */
      row.cells[0].classList = "cw_0";
      row.cells[1].classList = "cw_150";
      row.cells[2].classList = "cw_500";
      /* mark the text */ 
      if (r == 0) continue;
      var v_text = row.cells[2].textContent;
      var v_html = ""; var v_from = 0;
      var marks = JSON.parse(row.cells[0].textContent.replaceAll("O", "[").replaceAll("C", "]"));
      for (var m = 0; m < marks.length; m++) {
        v_html += 
          v_text.substr(v_from,marks[m][0]-v_from) + "<mark>" +
          v_text.substr(marks[m][0],marks[m][1]-marks[m][0]+1) + "</mark>";
        v_from = marks[m][1]+1;
      }
      v_html += v_text.substr(v_from);
      row.cells[2].innerHTML = v_html;
    }
  }
}

// install Google Search
// document.write('<script type="text/javascript" src="'
// + 'http://vanipedia.org/w/index.php?title=MediaWiki:GoogleSearch.js'
// + '&action=raw&ctype=text/javascript"></' + 'script>');

// install JQuery
//document.write('<script type="text/javascript" src="'
//+ 'http://vanipedia.org/w/index.php?title=MediaWiki:JQuery.js'
//+ '&action=raw&ctype=text/javascript"></' + 'script>');

// install WikEd toolbar and Vanify
//document.write('<script type="text/javascript" src="'
//+ 'http://vanipedia.org/w/index.php?title=MediaWiki:Vaniquotes.js'
//+ '&action=raw&ctype=text/javascript"></' + 'script>');
 
// install Replace
//document.write('<script type="text/javascript" src="'
//+ 'http://vanipedia.org/w/index.php?title=MediaWiki:TextboxReplace.js'
//+ '&action=raw&ctype=text/javascript"></' + 'script>');
 
// install Unify
//document.write('<script type="text/javascript" src="'
//+ 'http://vanipedia.org/w/index.php?title=MediaWiki:Unify.js'
//+ '&action=raw&ctype=text/javascript"></' + 'script>');
 
// install Vanify
//document.write('<script type="text/javascript" src="'
//+ 'http://vanipedia.org/w/index.php?title=MediaWiki:Vanify.js'
//+ '&action=raw&ctype=text/javascript"></' + 'script>');

// install Vani_suggest for diacritics auto-suggest pulldown on the search bar
//document.write('<script type="text/javascript" src="'
//+ 'http://vanipedia.org/w/index.php?title=MediaWiki:Vani_suggest.js'
//+ '&action=raw&ctype=text/javascript"></' + 'script>');

// install previous/next links for video categories in all languages
 //document.write('<script type="text/javascript" src="/navcat/navcat.js"></' + 'script>');
 
// Buttons
 
//addOnloadHook(function() {
 
//if (document.editform) {
//addPortletLink("p-cactions", "javascript:Unify()", "unify", "ca-unify", "Convert Balarama fonts to Unicode", "");
// addPortletLink("p-cactions", "javascript:Vanify()", "vanify", "ca-vanify", "Corrects vani markup", "");
// addPortletLink('p-cactions', 'javascript:format()', 'format', 'ca-format', 'Format article', '');
//addPortletLink('p-cactions', 'javascript:wpTextboxReplace()', 'Replace', 'ca-replace', 'Replaces text in the edit window', 'R');
//}
//});
 
// end Buttons

// --- YouTube Random Shorts (Kasya) ---
$(document).ready(function() {
    var $widget = $('.vani-shorts-viewport');
    
    if ($widget.length) {
        var $viewport = $widget;
        var $titleFrame = $widget.find('.vani-shorts-title');
        
        new mw.Api().get({
            action: 'query',
            prop: 'revisions',
            titles: 'VanimediaMayapur YouTube SHORTS List',
            rvprop: 'content',
            format: 'json'
        }).done(function(data) {
            try {
                var pages = data.query.pages;
                var pageId = Object.keys(pages)[0];
                
                if (pageId == "-1" || !pages[pageId].revisions) {
                    $viewport.text("Database list page not found.");
                    return;
                }
                
                // FIXED: Corrected MediaWiki revision array syntax lookup
                var rawWikiText = pages[pageId].revisions[0]['*'];
                var lines = rawWikiText.split('\n');
                var validShorts = [];
                
                for (var i = 0; i < lines.length; i++) {
                    var line = $.trim(lines[i]);
                    if (line.indexOf('File:') === 0 && line.toLowerCase().indexOf('link=') !== -1) {
                        validShorts.push(line);
                    }
                }
                
                if (validShorts.length === 0) {
                    $viewport.text("No gallery entries recognized.");
                    return;
                }
                
                var randomLine = validShorts[Math.floor(Math.random() * validShorts.length)];
                var parts = randomLine.split('|');
                
                // Reset defaults before parsing line elements
                var rawUrl = "";
                
                for (var j = 0; j < parts.length; j++) {
                    var part = $.trim(parts[j]);
                    
                    if (part.toLowerCase().indexOf('link=') === 0) {
                        rawUrl = part.substring(5).trim();
                    }
                }
                
                // Clean all template formatting brackets, space characters, and hidden control markers
                var urlCleaned = rawUrl.replace(/[\u200e\u200f\s\}\}\]]/g, ''); 
                
                // Direct YouTube Alphanumeric Pattern Matcher
                var idRegex = /(?:shorts\/|v=|embed\/|\/)([a-zA-Z0-9_-]{11})/;
                var matchResults = urlCleaned.match(idRegex);
                var videoId = "";
                
                if (matchResults && matchResults[1]) {
                    // FIXED: Grabbed index 1 to pull the standalone 11-digit ID without any slashes
                    videoId = matchResults[1].trim();
                }
                
                if (videoId && videoId.length === 11) {
                    // FIXED: Isolated to inject ONLY the video player iframe at the correct 280px width
                   var embedUrl = "https://www.youtube.com/embed/" + videoId;

                    $viewport.html('<iframe width="280" height="225" src="' + embedUrl + '" frameborder="0" allowfullscreen style="border-radius: 8px; border: none;"></iframe>');
                } else {
                    $viewport.html("<div style='color:#c0392b; padding:10px; font-size:11px;'>Invalid video ID sequence extracted.</div>");
                }
                
            } catch (err) {
                console.error("Shorts engine exception:", err);
                $viewport.text("Error handling text structure values.");
            }
        }).fail(function() {
            $viewport.text("API connection failed.");
        });
    }
});

// Kasya
/* Open Timeline links in a new tab ONLY on the Chapters page */
mw.hook('wikipage.content').add(function($content) {
    // Check if we are exactly on the timeline page
    if (mw.config.get('wgPageName') === "Chapters_in_Srila_Prabhupada's_Life") {
        
        // If yes, apply the new tab rule to the table
        $content.find('#mp-tfp a').attr('target', '_blank').attr('rel', 'noopener noreferrer');
    }
});

// Wait for MediaWiki core modules and the DOM to load
mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function () {
    $(document).ready(function () {
        
// 1. FIND THE "102 Languages" SIDEBAR SECTION
        var $sidebarMenu = $('#p-102_Languages ul').first();
        
        // Fallback in case your specific MediaWiki version formats the ID differently
        if ($sidebarMenu.length === 0) {
            $('.vector-menu-heading, .portal h3').each(function() {
                // Looks for the heading text directly
                if ($(this).text().trim() === '102 Languages') {
                    $sidebarMenu = $(this).closest('.vector-menu, .portal').find('ul').first();
                }
            });
        }
        
        // Exit if the 102 Languages menu isn't found on the page
        if (!$sidebarMenu || $sidebarMenu.length === 0) return;

        // 2. CREATE THE SEARCH BAR AS A MENU ITEM
        var $searchLi = $('<li id="n-language-search" style="margin-top: 10px; margin-bottom: 5px; list-style: none;"></li>');
        var $searchBox = $('<input type="text" id="sidebarLanguageSearch" placeholder="Search 102 Languages..." style="width: 100%; box-sizing: border-box; padding: 5px; font-size: 0.85em; border: 1px solid #a2a9b1; border-radius: 2px;" autocomplete="off" />');
        
        // Container for the results (hidden by default)
        var $resultsContainer = $('<ul id="sidebarLanguageResults" style="list-style: none; padding: 0; margin: 4px 0 0 0; max-height: 200px; overflow-y: auto; border: 1px solid #eaecf0; background: #ffffff; display: none;"></ul>');

        // Build the menu item and append it to the sidebar
        $searchLi.append($searchBox).append($resultsContainer);
        $sidebarMenu.prepend($searchLi); 

        var api = new mw.Api();
        var languageList = [];

        // 3. FETCH LANGUAGES FROM THE CATEGORY VIA API IN THE BACKGROUND
        api.get({
            action: 'query',
            list: 'categorymembers',
            cmtitle: 'Category:Languages_with_Total_Pages',
            cmlimit: 'max', 
            format: 'json'
        }).done(function (data) {
            if (data.query && data.query.categorymembers) {
                languageList = data.query.categorymembers.map(function (member) {
                    return {
                        title: member.title,
                        url: mw.util.getUrl(member.title) 
                    };
                });
            }
        });

        // 4. ADD SEARCH FUNCTIONALITY TO THE SIDEBAR BOX
        $('#sidebarLanguageSearch').on('keyup', function (e) {
            e.stopPropagation(); 
            var searchTerm = $(this).val().toLowerCase();
            $resultsContainer.empty();

            // Hide the results box if the search is empty
            if (searchTerm.length === 0) {
                $resultsContainer.hide();
                return; 
            }

            // Filter the fetched languages
            var filteredLanguages = languageList.filter(function (lang) {
                return lang.title.toLowerCase().indexOf(searchTerm) > -1;
            });

            // Show results container
            $resultsContainer.show();

            // Append results using Vector's standard dark text color
            if (filteredLanguages.length > 0) {
                filteredLanguages.forEach(function (lang) {
                    $resultsContainer.append('<li style="padding: 4px 6px; border-bottom: 1px solid #f8f9fa;"><a href="' + lang.url + '" style="text-decoration: none; color: #0645ad; display: block; font-size: 0.9em;">' + lang.title + '</a></li>');
                });
            } else {
                $resultsContainer.append('<li style="padding: 4px 6px; color: #72777d; font-size: 0.9em;">No languages found</li>');
            }
        });

        // Prevent typing from accidentally triggering global keyboard shortcuts
        $('#sidebarLanguageSearch').on('keydown', function(e) {
            e.stopPropagation();
        });
        
        // Optional: Hide results when clicking outside the sidebar search
        $(document).on('click', function(e) {
            if (!$(e.target).closest('#n-language-search').length) {
                $resultsContainer.hide();
            }
        });
        
        // Re-show results if they click back into the search box
        $('#sidebarLanguageSearch').on('click', function() {
            if ($(this).val().length > 0) {
                $resultsContainer.show();
            }
        });
        
    });
});

// 5. SIDEBAR ACCORDION - STRICT LEFT-COLUMN ISOLATION & TRUE ACCORDION
(function() {
    // 1. Tag ONLY menus physically located in the left sidebar
    function tagSidebarMenus() {
        var allMenus = document.querySelectorAll('.vector-menu');
        for (var i = 0; i < allMenus.length; i++) {
            var menu = allMenus[i];
            
            // STRICT INCLUSION: Only tag menus inside the modern or legacy left sidebar containers
            if (menu.closest('#vector-main-menu, #mw-panel, #mw-navigation')) {
                menu.classList.add('vanipedia-sidebar-menu');
                
                // Collapse them by default if they have a heading
                if (menu.querySelector('.vector-menu-heading') && !menu.classList.contains('vanipedia-collapsed')) {
                    menu.classList.add('vanipedia-collapsed');
                }
            }
        }
    }
    
    // Run tagging immediately, and again on load as a failsafe
    tagSidebarMenus();
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', tagSidebarMenus);
    }

    // 2. Inject CSS targeted STRICTLY at our newly tagged custom class
    var style = document.createElement('style');
    style.textContent = 
        /* Widen only our tagged sidebar menus */
        '.vanipedia-sidebar-menu { width: 185px !important; } ' + 
        
        /* Core functional hiding rule */
        '.vanipedia-sidebar-menu.vanipedia-collapsed .vector-menu-content { display: none !important; } ' + 
        
        /* Bold, Dark Header */
        '.vanipedia-sidebar-menu .vector-menu-heading { ' +
        '   cursor: pointer !important; ' +
        '   background-color: #2c4c50 !important; ' +     
        '   border: 1px solid #1b3033 !important; ' +     
        '   border-radius: 4px !important; ' +            
        '   margin-bottom: 4px !important; ' +            
        '   padding: 10px 12px !important; ' +
        '   font-weight: 600 !important; ' +
        '   color: #ffffff !important; ' +                
        '   display: flex !important; ' +
        '   justify-content: space-between !important; ' + 
        '   align-items: center !important; ' +
        '   gap: 10px !important; ' + 
        '   transition: all 0.2s ease; ' +
        '} ' +
        
        /* Fix header corners when expanded */
        '.vanipedia-sidebar-menu:not(.vanipedia-collapsed) .vector-menu-heading { ' +
        '   border-radius: 4px 4px 0 0 !important; ' +
        '   margin-bottom: 0 !important; ' +
        '} ' +
        
        /* Hover effect */
        '.vanipedia-sidebar-menu .vector-menu-heading:hover { background-color: #385e63 !important; } ' +
        
        /* The dropdown caret */
        '.vanipedia-sidebar-menu .vector-menu-heading::after { ' +
        '   content: "▼"; ' + 
        '   font-size: 0.75em; ' +
        '   color: #ffffff !important; ' +
        '   transition: transform 0.2s ease; ' +
        '} ' +
        
        /* Rotate the arrow when collapsed */
        '.vanipedia-sidebar-menu.vanipedia-collapsed .vector-menu-heading::after { ' +
        '   transform: rotate(-90deg); ' +
        '} ' +

        /* The Expanded Content Area */
        '.vanipedia-sidebar-menu .vector-menu-content { ' +
        '   background-color: #eaeff0 !important; ' +     
        '   border: 1px solid #2c4c50 !important; ' +     
        '   border-top: none !important; ' +              
        '   border-radius: 0 0 4px 4px !important; ' +    
        '   padding: 0 0 4px 0 !important; ' + 
        '   margin-bottom: 6px !important; ' +            
        '   box-shadow: 0 3px 6px rgba(0,0,0,0.15) !important; ' + 
        '} ' +

        /* Reset the list styles */
        '.vanipedia-sidebar-menu .vector-menu-content ul { ' +
        '   list-style: none !important; ' +
        '   margin: 0 !important; ' +
        '   padding: 0 !important; ' +
        '} ' +

        /* Menu links */
        '.vanipedia-sidebar-menu .vector-menu-content li a { ' +
        '   display: block !important; ' +                
        '   padding: 8px 12px 8px 16px !important; ' +    
        '   color: #1b3033 !important; ' +                
        '   text-decoration: none !important; ' +         
        '   border-left: 3px solid transparent !important; ' + 
        '   border-bottom: 1px solid rgba(44, 76, 80, 0.1) !important; ' + 
        '   transition: all 0.15s ease !important; ' +
        '} ' +
        
        /* Remove separator from last item */
        '.vanipedia-sidebar-menu .vector-menu-content li:last-child a { ' +
        '   border-bottom: none !important; ' +
        '} ' +

        /* Hover effect for individual menu items */
        '.vanipedia-sidebar-menu .vector-menu-content li a:hover { ' +
        '   background-color: #dbe4e6 !important; ' +     
        '   border-left: 3px solid #2c4c50 !important; ' + 
        '   color: #000000 !important; ' +                
        '} ';
        
    document.head.appendChild(style);

    // 3. Helper function to collapse all of our securely tagged menus
    function collapseAllSidebarMenus() {
        var menus = document.querySelectorAll('.vanipedia-sidebar-menu');
        for (var i = 0; i < menus.length; i++) {
            menus[i].classList.add('vanipedia-collapsed');
        }
    }

    // 4. Intercept clicks for True Accordion Behavior
    document.addEventListener('click', function(e) {
        var heading = e.target.closest('.vector-menu-heading');
        if (!heading) return;

        // ONLY react if this click belongs to one of our tagged sidebar menus
        var navContainer = heading.closest('.vanipedia-sidebar-menu');
        if (navContainer) {
            var isAlreadyOpen = !navContainer.classList.contains('vanipedia-collapsed');
            
            // Forcefully collapse ALL left sidebar menus first
            collapseAllSidebarMenus();

            // Open the clicked one if it wasn't already open
            if (!isAlreadyOpen) {
                navContainer.classList.remove('vanipedia-collapsed');
            }
            
            e.stopPropagation();
            e.preventDefault();
        }
    }, true);
})();

mw.loader.using('mediawiki.user').then(function() {
    // Fetch the user's assigned groups
    var userGroups = mw.config.get('wgUserGroups') || [];
    
    // Define the roles that SHOULD see the administrative tabs
    var isAuthorized = userGroups.includes('sysop') || 
                       userGroups.includes('interface-admin') || 
                       userGroups.includes('Editor');
                       
    // If the user is not in one of those groups, restrict the UI
    if (!isAuthorized) {
        document.body.classList.add('restricted-ui');
    }
});

// Function to open accordion from TOC and jump there //

mw.hook('wikipage.content').add(function() {
    
    function handleAccordionTOC(hash) {
        if (!hash || hash === '#') return false;
        
        try {
            var targetId = hash.substring(1);
            var targetElement = document.getElementById(targetId) || document.getElementById(decodeURIComponent(targetId));
            
            if (!targetElement) return false;

            var $target = $(targetElement);
            // Match either h2 or h3
            var $heading = $target.is('h2, h3') ? $target : $target.closest('h2, h3');
            
            if (!$heading.length) return false;

            var $accordion = $heading.next('.book-accordion');
            
            // If the heading itself is not followed directly by an accordion, 
            // check if the heading is located INSIDE a parent accordion (e.g., nested h3)
            var $parentAccordions = $heading.parents('.book-accordion');

            // If there's no direct accordion next to it and it's not inside any accordion,
            // let the browser handle standard jump.
            if (!$accordion.length && !$parentAccordions.length) return false;

            // 1. Open all ancestor accordions (if target heading is nested inside one)
            $parentAccordions.each(function() {
                var $parentCollapsible = $(this).children('.mw-collapsible');
                if ($parentCollapsible.length && $parentCollapsible.hasClass('mw-collapsed')) {
                    var pId = $parentCollapsible.attr('id');
                    if (pId) {
                        var pToggleClass = pId.replace('mw-customcollapsible-', 'mw-customtoggle-');
                        $('.' + pToggleClass).first().click();
                    }
                }
            });

            // 2. Open the accordion immediately following this heading (if present)
            if ($accordion.length) {
                var $collapsible = $accordion.children('.mw-collapsible, .mw-collapsible-content').first();
                if (!$collapsible.length) {
                    $collapsible = $accordion.find('.mw-collapsible');
                }
                
                if ($collapsible.length && $collapsible.hasClass('mw-collapsed')) {
                    var collapsibleId = $collapsible.attr('id'); 
                    if (collapsibleId) {
                        var toggleClass = collapsibleId.replace('mw-customcollapsible-', 'mw-customtoggle-');
                        $('.' + toggleClass).first().click();
                    }
                }
            }

            // Target element to scroll to (the accordion, or the heading itself if accordion is missing)
            var $scrollTarget = $accordion.length ? $accordion : $heading;

            // 3. Scroll to the visible section
            setTimeout(function() {
                $('html, body').animate({
                    scrollTop: $scrollTarget.offset().top - 75
                }, 300);
            }, 100);

            // Return true to indicate we successfully handled the TOC accordion click
            return true;

        } catch (e) {
            console.error("TOC Accordion script error:", e);
            return false;
        }
    }

    $(document).off('click.tocAccordion').on('click.tocAccordion', 'a[href^="#"]', function(e) {
        if ($(this).closest('#toc, .toc, .vector-toc').length > 0) {
            var href = $(this).attr('href');
            
            // Run our function to see if this is an accordion/heading link
            var isAccordion = handleAccordionTOC(href);
            
            // ONLY stop the default browser jump if we handled it
            if (isAccordion) {
                e.preventDefault(); 
                
                // Update the URL manually so the user can still share the link
                if (history.pushState) {
                    history.pushState(null, null, href);
                } else {
                    window.location.hash = href;
                }
            }
        }
    });

    if (window.location.hash) {
        setTimeout(function() {
            handleAccordionTOC(window.location.hash);
        }, 500);
    }
});

/* Sticky burger menu - Pure Floating Dropdown (Forces Unpinned & Full Title) */
(function () {
    let isMenuOpen = false;

    // 1. Force the sidebar out of pinned mode and return menu into the dropdown container
    function forceUnpinSidebar() {
        document.documentElement.classList.remove('vector-feature-main-menu-pinned-enabled', 'vector-feature-main-menu-pinned-clientpref-1');
        document.documentElement.classList.add('vector-feature-main-menu-pinned-disabled', 'vector-feature-main-menu-pinned-clientpref-0');
        if (document.body) {
            document.body.classList.remove('vector-feature-main-menu-pinned-enabled', 'vector-feature-main-menu-pinned-clientpref-1');
            document.body.classList.add('vector-feature-main-menu-pinned-disabled', 'vector-feature-main-menu-pinned-clientpref-0');
        }

        // Clear stored pin preference
        document.cookie = "vector-feature-main-menu-pinned=0; path=/; max-age=31536000";
        try { localStorage.setItem('vector-feature-main-menu-pinned', '0'); } catch(e) {}

        // If #vector-main-menu was moved into the pinned container, move it back into dropdown
        const mainMenu = document.getElementById('vector-main-menu');
        const unpinnedContainer = document.getElementById('vector-main-menu-unpinned-container') || 
                                  document.querySelector('#vector-main-menu-dropdown .vector-dropdown-content');
        const pinnedContainer = document.getElementById('vector-main-menu-pinned-container');

        if (mainMenu && unpinnedContainer && pinnedContainer && pinnedContainer.contains(mainMenu)) {
            unpinnedContainer.appendChild(mainMenu);
        }
    }

    function getDropdownElement() {
        return document.querySelector('#vector-main-menu-dropdown .vector-dropdown-content') || 
               document.getElementById('vector-main-menu-dropdown-content') ||
               document.getElementById('vector-main-menu-unpinned-container') ||
               document.getElementById('vector-main-menu');
    }

    function openMenu(menuBtn) {
        forceUnpinSidebar();

        const checkbox = document.getElementById('vector-main-menu-dropdown-checkbox');
        const dropdown = getDropdownElement();
        if (!dropdown) return;

        if (checkbox) {
            checkbox.checked = true;
            checkbox.dispatchEvent(new Event('change', { bubbles: true }));
        }

        const rect = menuBtn.getBoundingClientRect();
        dropdown.style.setProperty('position', 'fixed', 'important');
        dropdown.style.setProperty('top', rect.bottom + 'px', 'important');
        dropdown.style.setProperty('left', rect.left + 'px', 'important');
        dropdown.style.setProperty('z-index', '99999', 'important');
        dropdown.style.setProperty('max-height', (window.innerHeight - rect.bottom - 16) + 'px', 'important');
        dropdown.style.setProperty('overflow-y', 'auto', 'important');
        dropdown.style.setProperty('display', 'block', 'important');
        dropdown.style.setProperty('visibility', 'visible', 'important');
        dropdown.style.setProperty('opacity', '1', 'important');
        dropdown.style.setProperty('background-color', 'var(--background-color-base, #ffffff)', 'important');
        dropdown.style.setProperty('box-shadow', '0 4px 16px rgba(0, 0, 0, 0.2)', 'important');
        dropdown.style.setProperty('border-radius', '4px', 'important');

        isMenuOpen = true;
    }

    function closeMenu() {
        const checkbox = document.getElementById('vector-main-menu-dropdown-checkbox');
        const dropdown = getDropdownElement();
        if (!dropdown) return;

        if (checkbox) {
            checkbox.checked = false;
            checkbox.dispatchEvent(new Event('change', { bubbles: true }));
        }

        dropdown.style.removeProperty('position');
        dropdown.style.removeProperty('top');
        dropdown.style.removeProperty('left');
        dropdown.style.removeProperty('z-index');
        dropdown.style.removeProperty('max-height');
        dropdown.style.removeProperty('overflow-y');
        dropdown.style.removeProperty('background-color');
        dropdown.style.removeProperty('box-shadow');
        dropdown.style.removeProperty('border-radius');
        dropdown.style.setProperty('display', 'none', 'important');
        dropdown.style.setProperty('visibility', 'hidden', 'important');
        dropdown.style.setProperty('opacity', '0', 'important');

        isMenuOpen = false;
    }

    function initStickyBurger() {
        forceUnpinSidebar();

        const stickyHeader = document.getElementById('vector-sticky-header');
        if (!stickyHeader) return false;
        if (document.getElementById('vanipedia-sticky-main-menu')) return true;

        // 1. Create burger button
        const menuBtn = document.createElement('div');
        menuBtn.id = 'vanipedia-sticky-main-menu';
        menuBtn.title = 'Main menu';
        menuBtn.style.cursor = 'pointer'; 
        menuBtn.className = 'vector-dropdown-label cdx-button cdx-button--fake-button cdx-button--icon-only';

        // 2. Add hamburger icon
        const iconSpan = document.createElement('span');
        iconSpan.className = 'vector-icon mw-ui-icon-menu mw-ui-icon-wikimedia-menu'; 
        menuBtn.appendChild(iconSpan);

        // 3. Toggle click handler (1st click opens, 2nd click rolls back)
        menuBtn.addEventListener('click', function (e) {
            e.preventDefault();
            e.stopPropagation();

            if (isMenuOpen) {
                closeMenu();
            } else {
                openMenu(menuBtn);
            }
        });

        // 4. Inject into start container
        let startContainer = stickyHeader.querySelector('.vector-sticky-header-start');
        if (!startContainer) {
            startContainer = document.createElement('div');
            startContainer.className = 'vector-sticky-header-start';
            stickyHeader.insertBefore(startContainer, stickyHeader.firstChild);
        }
        
        startContainer.insertBefore(menuBtn, startContainer.firstChild);
        return true;
    }

    // 5. Close when clicking anywhere outside
    document.addEventListener('click', function (e) {
        if (!isMenuOpen) return;
        const menuBtn = document.getElementById('vanipedia-sticky-main-menu');
        const dropdown = getDropdownElement();
        if (dropdown && menuBtn && !menuBtn.contains(e.target) && !dropdown.contains(e.target)) {
            closeMenu();
        }
    });

    // 6. Bootstrap initializer
    if (!initStickyBurger()) {
        const checkTimer = setInterval(function () {
            if (initStickyBurger()) {
                clearInterval(checkTimer);
            }
        }, 100);
        setTimeout(function () { clearInterval(checkTimer); }, 4000);
    }

    mw.hook('wikipage.content').add(initStickyBurger);
    $(initStickyBurger);
})();

/* Floating "Back to Top" Button Controller */
(function () {
    function initBackToTop() {
        if (document.getElementById('vanipedia-back-to-top')) return;

        // 1. Create button element with an up-arrow SVG icon
        const btn = document.createElement('button');
        btn.id = 'vanipedia-back-to-top';
        btn.title = 'Back to top';
        btn.setAttribute('aria-label', 'Back to top');
        
        btn.innerHTML = `
            <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <polyline points="18 15 12 9 6 15"></polyline>
            </svg>
        `;

        // 2. Smooth scroll to top on click
        btn.addEventListener('click', function (e) {
            e.preventDefault();
            window.scrollTo({ top: 0, behavior: 'smooth' });
        });

        // 3. Show button only after scrolling down 300px
        function toggleVisibility() {
            if (window.scrollY > 300) {
                btn.classList.add('visible');
            } else {
                btn.classList.remove('visible');
            }
        }

        window.addEventListener('scroll', toggleVisibility, { passive: true });
        toggleVisibility();

        document.body.appendChild(btn);
    }

    $(initBackToTop);
    mw.hook('wikipage.content').add(initBackToTop);
})();