Jump to content

MediaWiki:Common.js: Difference between revisions

From Utopia Game
No edit summary
No edit summary
Line 116: Line 116:
     });
     });
     observer.observe(document.body, { childList: true, subtree: true });
     observer.observe(document.body, { childList: true, subtree: true });
});
// ===============================
// Sticky Header Game Time
// Display: "Mar 1 YR1"
// Rules:
// - Each real hour = in-game Day (1..24)
// - Each real day = in-game Month (Jan..Jul cycle, 7-day loop)
// - Each 7 real days = new in-game Year
// ===============================
mw.hook('wikipage.content').add(function () {
    const icons = document.querySelector('.vector-sticky-header-icons');
    if (!icons) return;
    if (document.getElementById('sticky-game-time')) return;
    const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul'];
    // --------- ANCHOR (set "right now" to Mar 1 YR1) ----------
    // This locks the current real-day to month "Mar" and year "YR1".
    const ANCHOR_MONTH_INDEX = 2; // Mar (Jan=0)
    const ANCHOR_YEAR = 1;
    // Optional: if your game day/month rollover follows a timezone offset from UTC,
    // set this (e.g., New York is -5 or -4 depending on DST; UTC is 0).
    const GAME_TZ_OFFSET_HOURS = 0;
    // Create UI pill
    const wrap = document.createElement('span');
    wrap.id = 'sticky-game-time';
    wrap.className = 'sticky-game-time';
    const value = document.createElement('span');
    value.className = 'sticky-game-time__value';
    wrap.appendChild(value);
    icons.prepend(wrap);
    function getShiftedNow() {
        return new Date(Date.now() + GAME_TZ_OFFSET_HOURS * 3600000);
    }
    // Anchor "day start" (midnight) in the shifted timezone
    const anchorNow = getShiftedNow();
    const anchorDayStart = new Date(Date.UTC(
        anchorNow.getUTCFullYear(),
        anchorNow.getUTCMonth(),
        anchorNow.getUTCDate(),
        0, 0, 0, 0
    ));
    // Total day index at anchor (year-1)*7 + monthIndex
    const anchorTotalDayIndex = (ANCHOR_YEAR - 1) * 7 + ANCHOR_MONTH_INDEX;
    function computeGameString() {
        const now = getShiftedNow();
        // Start of "today" in shifted timezone
        const dayStart = new Date(Date.UTC(
            now.getUTCFullYear(),
            now.getUTCMonth(),
            now.getUTCDate(),
            0, 0, 0, 0
        ));
        // Days since anchor (drives Month and Year)
        const daysPassed = Math.floor((dayStart.getTime() - anchorDayStart.getTime()) / 86400000);
        const totalDayIndex = anchorTotalDayIndex + daysPassed;
        const year = Math.floor(totalDayIndex / 7) + 1;
        const month = months[((totalDayIndex % 7) + 7) % 7];
        // Hour-of-day drives Day number (1..24)
        const hour = now.getUTCHours(); // 0..23
        const dayNumber = hour + 1;
        return `${month} ${dayNumber} YR${year}`;
    }
    function update() {
        value.textContent = computeGameString();
    }
    // Update now
    update();
    // Update exactly on the next hour, then hourly
    const now0 = getShiftedNow();
    const msUntilNextHour =
        3600000 - (now0.getUTCMinutes() * 60000 + now0.getUTCSeconds() * 1000 + now0.getUTCMilliseconds());
    setTimeout(function () {
        update();
        setInterval(update, 3600000);
    }, msUntilNextHour);
});
});

Revision as of 13:25, 13 February 2026

/* Any JavaScript here will be loaded for all users on every page load. */

// Tab functionality
$(document).ready(function() {
    // Initialize tabs - show first tab by default
    $('.wiki-tabs-container').each(function() {
        var $container = $(this);
        var $firstButton = $container.find('.wiki-tab-button').first();
        var firstTabId = $firstButton.data('tab');
        
        $firstButton.addClass('active');
        $container.find('#' + firstTabId).addClass('active').show();
    });
    
    // Tab click handler
    $('.wiki-tab-button').on('click', function() {
        var $button = $(this);
        var tabId = $button.data('tab');
        var $container = $button.closest('.wiki-tabs-container');
        
        // Remove active class from all buttons and panes in this container
        $container.find('.wiki-tab-button').removeClass('active');
        $container.find('.wiki-tab-pane').removeClass('active').hide();
        
        // Add active class to clicked button and corresponding pane
        $button.addClass('active');
        $container.find('#' + tabId).addClass('active').show();
    });
});

// ===============================
// Add Custom Sticky Header Link
// ===============================
mw.hook('wikipage.content').add(function () {

    const icons = document.querySelector('.vector-sticky-header-icons');
    if (!icons) return;

    // Prevent duplicate button on navigation
    if (document.getElementById('custom-sticky-link')) return;

    const link = document.createElement('a');
    link.id = 'custom-sticky-link';
    link.href = 'https://discord.gg/t2Rp2dRvze'; // CHANGE THIS
    link.target = '_blank';
    link.className = 'cdx-button cdx-button--fake-button cdx-button--fake-button--enabled cdx-button--weight-quiet';
    link.textContent = 'Join Us on Discord!'; // CHANGE TEXT
    link.style.marginLeft = '10px';
    link.style.fontWeight = 'bold';

    icons.prepend(link); // use appendChild() if you want it at the end
});

// ===============================
// Sticky Header Countdown Timer (Vector 2022) - to Apr 18, 2026 00:00 UTC
// ===============================
mw.hook('wikipage.content').add(function () {
    const icons = document.querySelector('.vector-sticky-header-icons');
    if (!icons) return;

    // Prevent duplicates
    if (document.getElementById('sticky-countdown')) return;

    // Target: Sat, 18 Apr 2026 at 00:00 GMT+00:00 (UTC)
    const target = new Date('2026-04-18T00:00:00Z');

    const wrap = document.createElement('span');
    wrap.id = 'sticky-countdown';
    wrap.className = 'sticky-countdown';

    const label = document.createElement('span');
    label.className = 'sticky-countdown__label';
    label.textContent = 'Ends in:';

    const value = document.createElement('span');
    value.className = 'sticky-countdown__value';
    value.textContent = '--:--:--';

    wrap.appendChild(label);
    wrap.appendChild(value);

    // Put it before the default icons (Talk/History/Edit)
    icons.prepend(wrap);

    const pad = (n) => String(n).padStart(2, '0');

    const formatRemaining = (ms) => {
        if (ms <= 0) return '00:00:00';
        const totalSeconds = Math.floor(ms / 1000);

        const days = Math.floor(totalSeconds / 86400);
        const hours = Math.floor((totalSeconds % 86400) / 3600);
        const minutes = Math.floor((totalSeconds % 3600) / 60);
        const seconds = totalSeconds % 60;

        if (days > 0) return `${days}d ${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
        return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
    };

    const update = () => {
        const now = new Date();
        const diff = target.getTime() - now.getTime();
        value.textContent = formatRemaining(diff);
        wrap.classList.toggle('is-expired', diff <= 0);
    };

    update();
    const timerId = window.setInterval(update, 1000);

    // Cleanup if element removed (rare, but safe)
    const observer = new MutationObserver(() => {
        if (!document.getElementById('sticky-countdown')) {
            clearInterval(timerId);
            observer.disconnect();
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });
});

// ===============================
// Sticky Header Game Time
// Display: "Mar 1 YR1"
// Rules:
// - Each real hour = in-game Day (1..24)
// - Each real day = in-game Month (Jan..Jul cycle, 7-day loop)
// - Each 7 real days = new in-game Year
// ===============================
mw.hook('wikipage.content').add(function () {
    const icons = document.querySelector('.vector-sticky-header-icons');
    if (!icons) return;

    if (document.getElementById('sticky-game-time')) return;

    const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul'];

    // --------- ANCHOR (set "right now" to Mar 1 YR1) ----------
    // This locks the current real-day to month "Mar" and year "YR1".
    const ANCHOR_MONTH_INDEX = 2; // Mar (Jan=0)
    const ANCHOR_YEAR = 1;

    // Optional: if your game day/month rollover follows a timezone offset from UTC,
    // set this (e.g., New York is -5 or -4 depending on DST; UTC is 0).
    const GAME_TZ_OFFSET_HOURS = 0;

    // Create UI pill
    const wrap = document.createElement('span');
    wrap.id = 'sticky-game-time';
    wrap.className = 'sticky-game-time';

    const value = document.createElement('span');
    value.className = 'sticky-game-time__value';

    wrap.appendChild(value);
    icons.prepend(wrap);

    function getShiftedNow() {
        return new Date(Date.now() + GAME_TZ_OFFSET_HOURS * 3600000);
    }

    // Anchor "day start" (midnight) in the shifted timezone
    const anchorNow = getShiftedNow();
    const anchorDayStart = new Date(Date.UTC(
        anchorNow.getUTCFullYear(),
        anchorNow.getUTCMonth(),
        anchorNow.getUTCDate(),
        0, 0, 0, 0
    ));

    // Total day index at anchor (year-1)*7 + monthIndex
    const anchorTotalDayIndex = (ANCHOR_YEAR - 1) * 7 + ANCHOR_MONTH_INDEX;

    function computeGameString() {
        const now = getShiftedNow();

        // Start of "today" in shifted timezone
        const dayStart = new Date(Date.UTC(
            now.getUTCFullYear(),
            now.getUTCMonth(),
            now.getUTCDate(),
            0, 0, 0, 0
        ));

        // Days since anchor (drives Month and Year)
        const daysPassed = Math.floor((dayStart.getTime() - anchorDayStart.getTime()) / 86400000);

        const totalDayIndex = anchorTotalDayIndex + daysPassed;
        const year = Math.floor(totalDayIndex / 7) + 1;
        const month = months[((totalDayIndex % 7) + 7) % 7];

        // Hour-of-day drives Day number (1..24)
        const hour = now.getUTCHours(); // 0..23
        const dayNumber = hour + 1;

        return `${month} ${dayNumber} YR${year}`;
    }

    function update() {
        value.textContent = computeGameString();
    }

    // Update now
    update();

    // Update exactly on the next hour, then hourly
    const now0 = getShiftedNow();
    const msUntilNextHour =
        3600000 - (now0.getUTCMinutes() * 60000 + now0.getUTCSeconds() * 1000 + now0.getUTCMilliseconds());

    setTimeout(function () {
        update();
        setInterval(update, 3600000);
    }, msUntilNextHour);
});