MediaWiki:Common.js: Difference between revisions

From Winds Of Valen Wiki
Jump to navigation Jump to search
Update Discord injection to be simple button
Switched to use CSS class for passing arguments
 
(7 intermediate revisions by the same user not shown)
Line 1: Line 1:
/**
$(document).ready(function() {
* Winds of Valen Wiki — Common JS
    $('#ca-nstab-main a').text('Article');
*/
    $('#ca-history a').text('History');
    $('#ca-view a').text('Read');
});
// Skill Calculator logic to be embedded in MediaWiki:Common.js
mw.hook('wikipage.content').add(function($content) {
    // Only run if the page contains a calculator container
    const calcContainer = $content.find('#wiki-skill-calc')[0];
    if (!calcContainer) return;
    if (calcContainer.dataset.initialized) return;
    calcContainer.dataset.initialized = 'true';


/* 1. Force light color scheme immediately (before paint) */
    const skillClass = Array.from(calcContainer.classList).find(c => c.startsWith('skill-'));
(function () {
    if (!skillClass) {
    document.documentElement.style.colorScheme = 'light';
        calcContainer.innerHTML = "<p style='color:red;'>Error: No skill class found on container.</p>";
}());
        return;
    }
    const currentSkill = skillClass.replace('skill-', ''); // e.g., "Mining"


/* 2. Fix Vector 2022 sidebar: switch pinned-disabled → pinned-enabled */
    // Raw XP Table (Level 1 to 99)
(function () {
     const xpTable = [
     var h = document.documentElement;
         0, 0, 74, 160, 258, 371, 500, 649, 820, 1016, 1241, 1500, 1797, 2139, 2531, 2982, 3500, 4095, 4778, 5563, 6464, 7500, 8690, 10056, 11626, 13429, 15500, 17879, 20612, 23751, 27358, 31500, 36258, 41724, 48003, 55215, 63500, 73017, 83949, 96506, 110930, 127500, 146533, 168397, 193512, 222361, 255500, 293567, 337294, 387523, 445222, 511500, 587634, 675088, 775547, 890944, 1023500, 1175767, 1350676, 1551594, 1782388, 2047500, 2352034, 2701852, 3103688, 3565275, 4095500, 4704568, 5404204, 6207875, 7131050, 8191500, 9409637, 10808909, 12416250, 14262600, 16383500, 18819774, 21618318, 24833000, 28525701, 32767500, 37640048, 43237135, 49666500, 57051902, 65535500, 75280595, 86474770, 99333501, 114104303, 131071500, 150561691, 172950041, 198667502, 228209107, 262143500, 301123982, 345900582, 397335504
    h.className = h.className
    ];
         .replace('vector-feature-main-menu-pinned-disabled', 'vector-feature-main-menu-pinned-enabled');
}());


/* 3. Load Cinzel + Inter fonts */
    // Data compiled from the scraped files
(function () {
    const skillData = {
    if (!document.getElementById('wov-fonts')) {
        "Mining": [
         var l = document.createElement('link');
            { "name": "Copper Ore", "reqLevel": 1, "xp": 15 },
         l.id = 'wov-fonts';
            { "name": "Tin Ore", "reqLevel": 1, "xp": 15 },
         l.rel = 'stylesheet';
            { "name": "Iron Ore", "reqLevel": 10, "xp": 30 },
         l.href = 'https://fonts.googleapis.com/css2?family=Cinzel:wght@700&family=PT+Serif:ital,wght@0,400;0,700;1,400&family=Inter:wght@400;600&display=swap';
            { "name": "Coal Ore", "reqLevel": 20, "xp": 80 },
         document.head.appendChild(l);
            { "name": "Mithril Ore", "reqLevel": 30, "xp": 150 },
            { "name": "Gold Ore", "reqLevel": 40, "xp": 350 },
            { "name": "Essence Geode", "reqLevel": 50, "xp": 550 }
         ],
         "Fishing": [
            { "name": "Minnow", "reqLevel": 1, "xp": 8 },
            { "name": "Common Trout", "reqLevel": 5, "xp": 75 },
            { "name": "Perch", "reqLevel": 10, "xp": 225 },
            { "name": "Bass", "reqLevel": 20, "xp": 200 },
            { "name": "Blue Gill", "reqLevel": 30, "xp": 75 },
            { "name": "Elder Trout", "reqLevel": 40, "xp": 500 },
            { "name": "Carp", "reqLevel": 50, "xp": 1250 }
         ],
         "PotionMaking": [
            { "name": "Weak Health Potion", "reqLevel": 1, "xp": 25 },
            { "name": "Health Potion", "reqLevel": 10, "xp": 100 },
            { "name": "Attack Potion", "reqLevel": 25, "xp": 1500 },
            { "name": "Fishing Potion", "reqLevel": 30, "xp": 2000 },
            { "name": "Mining Potion", "reqLevel": 30, "xp": 2000 },
            { "name": "Shield Potion", "reqLevel": 40, "xp": 3500 },
            { "name": "Strong Health Potion", "reqLevel": 50, "xp": 5000 },
            { "name": "Strong Shield Potion", "reqLevel": 60, "xp": 8000 }
        ]
    };
 
    const actions = skillData[currentSkill];
    if (!actions) {
         calcContainer.innerHTML = "<p style='color:red;'>Calculator data not found for " + currentSkill + ".</p>";
        return;
     }
     }
}());


document.addEventListener('DOMContentLoaded', function () {
    // Convert level to XP
    function levelToXP(level) {
        if (level < 1) return xpTable[1];
        if (level > 99) return xpTable[99];
        return xpTable[level];
    }


     /* 4. Move main menu from hamburger dropdown into pinned sidebar slot */
     function calculateActions(currentXP, targetXP) {
    var pinned  = document.getElementById('vector-main-menu-pinned-container');
        const xpNeeded = targetXP - currentXP;
    var unpinned = document.getElementById('vector-main-menu-unpinned-container');
        if (xpNeeded <= 0) return [];
    if (pinned && unpinned && unpinned.children.length > 0 && pinned.children.length === 0) {
         return actions.map(action => {
         while (unpinned.firstChild) {
             const amount = Math.ceil(xpNeeded / action.xp);
             pinned.appendChild(unpinned.firstChild);
            return { ...action, amount, xpNeeded };
         }
         }).sort((a, b) => a.reqLevel - b.reqLevel);
     }
     }


     /* 5. Hide hamburger button since sidebar is now always visible */
     function renderCalculator() {
    var ham = document.getElementById('vector-main-menu-dropdown');
        const currentLvl = parseInt(document.getElementById('calc-current-lvl').value) || 1;
    if (ham) ham.style.display = 'none';
        const targetLvl = parseInt(document.getElementById('calc-target-lvl').value) || (currentLvl + 1);


    /* 6. Inject Logo banner + Discord button at top of sidebar */
        const currentXP = levelToXP(currentLvl);
    var sidebarEl = pinned || document.getElementById('vector-main-menu');
         const targetXP = levelToXP(targetLvl);
    if (sidebarEl) {
         const xpNeeded = targetXP - currentXP;
         var logoImg = document.querySelector('#p-logo img, #p-logo .mw-logo-icon');
         var logoSrc = logoImg ? logoImg.src : '';


         /* Logo Banner */
         let html = `
        var logoDiv = document.createElement('div');
            <div class="calc-results-header">
        logoDiv.className = 'wov-sidebar-logo';
                <h3>XP Required: <span>${xpNeeded.toLocaleString()}</span></h3>
        logoDiv.innerHTML =
                <p>From Level ${currentLvl} (${currentXP.toLocaleString()} XP) to Level ${targetLvl} (${targetXP.toLocaleString()} XP)</p>
            '<a href="/wiki/Main_Page">' +
             </div>
            (logoSrc ? '<img src="' + logoSrc + '" alt="Winds of Valen Wiki" />' : '') +
            <table class="wikitable calc-table">
             '<div class="wov-sidebar-logo-title">Winds of Valen</div>' +
                <tr><th>Action</th><th>Level Req.</th><th>XP/Action</th><th>Total Actions</th></tr>
            '<div class="wov-sidebar-logo-sub">Wiki</div>' +
         `;
            '</a>';
         sidebarEl.insertBefore(logoDiv, sidebarEl.firstChild);


         /* Simple HTML Discord Button */
         if (xpNeeded <= 0) {
         var discordDiv = document.createElement('div');
            html += `<tr><td colspan="4" style="text-align:center;">You have already reached the target level!</td></tr>`;
        discordDiv.style.padding = "10px";
         } else {
        discordDiv.innerHTML = '<a href="https://discord.gg/xxzDqg9xWc" class="wov-discord-btn-link" target="_blank" rel="noopener">Chat on Discord</a>';
            const results = calculateActions(currentXP, targetXP);
         sidebarEl.insertBefore(discordDiv, sidebarEl.children[1]);
            results.forEach(res => {
                const available = currentLvl >= res.reqLevel;
                const rowClass = available ? '' : 'calc-unavailable';
                const opacity = available ? '1' : '0.5';
                html += `
                    <tr class="${rowClass}" style="opacity: ${opacity}">
                        <td><strong>${res.name}</strong></td>
                        <td>${res.reqLevel}</td>
                        <td>${res.xp}</td>
                        <td><strong>${res.amount.toLocaleString()}</strong></td>
                    </tr>
                `;
            });
        }
        html += `</table>`;
         document.getElementById('calc-results').innerHTML = html;
     }
     }


     /* 7. Hide "Main Page" h1 on the Main Page only */
     // Inject CSS
     if (mw && mw.config && mw.config.get('wgPageName') === 'Main_Page') {
     const style = document.createElement('style');
         var h1 = document.getElementById('firstHeading');
    style.innerHTML = `
         if (h1) h1.style.display = 'none';
        .calc-wrapper {
         var mh = document.querySelector('.mw-first-heading');
            background: #1a1b26;
         if (mh) mh.style.display = 'none';
            color: #a9b1d6;
     }
            padding: 20px;
            border-radius: 8px;
            border: 1px solid #414868;
            max-width: 600px;
            margin: 20px 0;
            font-family: 'Inter', sans-serif;
            box-shadow: 0 10px 25px rgba(0,0,0,0.5);
        }
        .calc-wrapper h2 {
            margin-top: 0;
            color: #7aa2f7;
            border-bottom: 2px solid #24283b;
            padding-bottom: 10px;
        }
        .calc-inputs {
            display: flex;
            gap: 20px;
            margin-bottom: 20px;
        }
        .calc-input-group {
            display: flex;
            flex-direction: column;
            gap: 5px;
        }
        .calc-input-group label {
            font-size: 12px;
            text-transform: uppercase;
            font-weight: bold;
            color: #565f89;
        }
        .calc-input-group input {
            background: #24283b;
            border: 1px solid #414868;
            color: #c0caf5;
            padding: 10px;
            border-radius: 4px;
            width: 100px;
            font-size: 16px;
            font-weight: bold;
        }
         .calc-input-group input:focus {
            outline: none;
            border-color: #7aa2f7;
         }
        .calc-results-header h3 {
            color: #bb9af7;
            margin: 0 0 5px 0;
        }
        .calc-table {
            width: 100%;
            background: transparent !important;
            border: none !important;
            border-collapse: collapse;
         }
        .calc-table th {
            background: #24283b !important;
            color: #7dcfff !important;
            border: none !important;
            text-align: left;
            padding: 10px;
        }
        .calc-table td {
            border: none !important;
            border-bottom: 1px solid #24283b !important;
            padding: 10px;
            color: #c0caf5;
         }
        .calc-unavailable td {
            color: #565f89;
        }
        .calc-btn {
            margin-top: 19px;
            background: #7aa2f7;
            color: #1a1b26;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.2s ease;
        }
        .calc-btn:hover {
            background: #8caaee;
        }
    `;
    document.head.appendChild(style);
 
    // Initial Layout Setup
     calcContainer.innerHTML = `
        <div class="calc-wrapper">
            <h2>${currentSkill} Calculator</h2>
            <div class="calc-inputs">
                <div class="calc-input-group">
                    <label>Current Level</label>
                    <input type="number" id="calc-current-lvl" value="1" min="1" max="99">
                </div>
                <div class="calc-input-group">
                    <label>Target Level</label>
                    <input type="number" id="calc-target-lvl" value="10" min="2" max="99">
                </div>
                <button class="calc-btn" id="calc-refresh-btn">Calculate</button>
            </div>
            <div id="calc-results"></div>
        </div>
    `;


    /* 8. Make .wov-popular-btn spans behave as full-block links */
     document.getElementById('calc-current-lvl').addEventListener('change', renderCalculator);
     document.querySelectorAll('.wov-popular-grid a').forEach(function (a) {
    document.getElementById('calc-target-lvl').addEventListener('change', renderCalculator);
        a.style.display = 'block';
    document.getElementById('calc-refresh-btn').addEventListener('click', renderCalculator);
        a.style.textDecoration = 'none';
        var span = a.querySelector('.wov-popular-btn');
        if (span) {
            span.style.display = 'block';
        }
    });


    // Render initially
    renderCalculator();
});
});

Latest revision as of 19:17, 18 July 2026

$(document).ready(function() {
    $('#ca-nstab-main a').text('Article');
    $('#ca-history a').text('History');
    $('#ca-view a').text('Read');
});
// Skill Calculator logic to be embedded in MediaWiki:Common.js
mw.hook('wikipage.content').add(function($content) {
    // Only run if the page contains a calculator container
    const calcContainer = $content.find('#wiki-skill-calc')[0];
    if (!calcContainer) return;
    if (calcContainer.dataset.initialized) return;
    calcContainer.dataset.initialized = 'true';

    const skillClass = Array.from(calcContainer.classList).find(c => c.startsWith('skill-'));
    if (!skillClass) {
        calcContainer.innerHTML = "<p style='color:red;'>Error: No skill class found on container.</p>";
        return;
    }
    const currentSkill = skillClass.replace('skill-', ''); // e.g., "Mining"

    // Raw XP Table (Level 1 to 99)
    const xpTable = [
        0, 0, 74, 160, 258, 371, 500, 649, 820, 1016, 1241, 1500, 1797, 2139, 2531, 2982, 3500, 4095, 4778, 5563, 6464, 7500, 8690, 10056, 11626, 13429, 15500, 17879, 20612, 23751, 27358, 31500, 36258, 41724, 48003, 55215, 63500, 73017, 83949, 96506, 110930, 127500, 146533, 168397, 193512, 222361, 255500, 293567, 337294, 387523, 445222, 511500, 587634, 675088, 775547, 890944, 1023500, 1175767, 1350676, 1551594, 1782388, 2047500, 2352034, 2701852, 3103688, 3565275, 4095500, 4704568, 5404204, 6207875, 7131050, 8191500, 9409637, 10808909, 12416250, 14262600, 16383500, 18819774, 21618318, 24833000, 28525701, 32767500, 37640048, 43237135, 49666500, 57051902, 65535500, 75280595, 86474770, 99333501, 114104303, 131071500, 150561691, 172950041, 198667502, 228209107, 262143500, 301123982, 345900582, 397335504
    ];

    // Data compiled from the scraped files
    const skillData = {
        "Mining": [
            { "name": "Copper Ore", "reqLevel": 1, "xp": 15 },
            { "name": "Tin Ore", "reqLevel": 1, "xp": 15 },
            { "name": "Iron Ore", "reqLevel": 10, "xp": 30 },
            { "name": "Coal Ore", "reqLevel": 20, "xp": 80 },
            { "name": "Mithril Ore", "reqLevel": 30, "xp": 150 },
            { "name": "Gold Ore", "reqLevel": 40, "xp": 350 },
            { "name": "Essence Geode", "reqLevel": 50, "xp": 550 }
        ],
        "Fishing": [
            { "name": "Minnow", "reqLevel": 1, "xp": 8 },
            { "name": "Common Trout", "reqLevel": 5, "xp": 75 },
            { "name": "Perch", "reqLevel": 10, "xp": 225 },
            { "name": "Bass", "reqLevel": 20, "xp": 200 },
            { "name": "Blue Gill", "reqLevel": 30, "xp": 75 },
            { "name": "Elder Trout", "reqLevel": 40, "xp": 500 },
            { "name": "Carp", "reqLevel": 50, "xp": 1250 }
        ],
        "PotionMaking": [
            { "name": "Weak Health Potion", "reqLevel": 1, "xp": 25 },
            { "name": "Health Potion", "reqLevel": 10, "xp": 100 },
            { "name": "Attack Potion", "reqLevel": 25, "xp": 1500 },
            { "name": "Fishing Potion", "reqLevel": 30, "xp": 2000 },
            { "name": "Mining Potion", "reqLevel": 30, "xp": 2000 },
            { "name": "Shield Potion", "reqLevel": 40, "xp": 3500 },
            { "name": "Strong Health Potion", "reqLevel": 50, "xp": 5000 },
            { "name": "Strong Shield Potion", "reqLevel": 60, "xp": 8000 }
        ]
    };

    const actions = skillData[currentSkill];
    if (!actions) {
        calcContainer.innerHTML = "<p style='color:red;'>Calculator data not found for " + currentSkill + ".</p>";
        return;
    }

    // Convert level to XP
    function levelToXP(level) {
        if (level < 1) return xpTable[1];
        if (level > 99) return xpTable[99];
        return xpTable[level];
    }

    function calculateActions(currentXP, targetXP) {
        const xpNeeded = targetXP - currentXP;
        if (xpNeeded <= 0) return [];
        return actions.map(action => {
            const amount = Math.ceil(xpNeeded / action.xp);
            return { ...action, amount, xpNeeded };
        }).sort((a, b) => a.reqLevel - b.reqLevel);
    }

    function renderCalculator() {
        const currentLvl = parseInt(document.getElementById('calc-current-lvl').value) || 1;
        const targetLvl = parseInt(document.getElementById('calc-target-lvl').value) || (currentLvl + 1);

        const currentXP = levelToXP(currentLvl);
        const targetXP = levelToXP(targetLvl);
        const xpNeeded = targetXP - currentXP;

        let html = `
            <div class="calc-results-header">
                <h3>XP Required: <span>${xpNeeded.toLocaleString()}</span></h3>
                <p>From Level ${currentLvl} (${currentXP.toLocaleString()} XP) to Level ${targetLvl} (${targetXP.toLocaleString()} XP)</p>
            </div>
            <table class="wikitable calc-table">
                <tr><th>Action</th><th>Level Req.</th><th>XP/Action</th><th>Total Actions</th></tr>
        `;

        if (xpNeeded <= 0) {
            html += `<tr><td colspan="4" style="text-align:center;">You have already reached the target level!</td></tr>`;
        } else {
            const results = calculateActions(currentXP, targetXP);
            results.forEach(res => {
                const available = currentLvl >= res.reqLevel;
                const rowClass = available ? '' : 'calc-unavailable';
                const opacity = available ? '1' : '0.5';
                html += `
                    <tr class="${rowClass}" style="opacity: ${opacity}">
                        <td><strong>${res.name}</strong></td>
                        <td>${res.reqLevel}</td>
                        <td>${res.xp}</td>
                        <td><strong>${res.amount.toLocaleString()}</strong></td>
                    </tr>
                `;
            });
        }
        html += `</table>`;
        document.getElementById('calc-results').innerHTML = html;
    }

    // Inject CSS
    const style = document.createElement('style');
    style.innerHTML = `
        .calc-wrapper {
            background: #1a1b26;
            color: #a9b1d6;
            padding: 20px;
            border-radius: 8px;
            border: 1px solid #414868;
            max-width: 600px;
            margin: 20px 0;
            font-family: 'Inter', sans-serif;
            box-shadow: 0 10px 25px rgba(0,0,0,0.5);
        }
        .calc-wrapper h2 {
            margin-top: 0;
            color: #7aa2f7;
            border-bottom: 2px solid #24283b;
            padding-bottom: 10px;
        }
        .calc-inputs {
            display: flex;
            gap: 20px;
            margin-bottom: 20px;
        }
        .calc-input-group {
            display: flex;
            flex-direction: column;
            gap: 5px;
        }
        .calc-input-group label {
            font-size: 12px;
            text-transform: uppercase;
            font-weight: bold;
            color: #565f89;
        }
        .calc-input-group input {
            background: #24283b;
            border: 1px solid #414868;
            color: #c0caf5;
            padding: 10px;
            border-radius: 4px;
            width: 100px;
            font-size: 16px;
            font-weight: bold;
        }
        .calc-input-group input:focus {
            outline: none;
            border-color: #7aa2f7;
        }
        .calc-results-header h3 {
            color: #bb9af7;
            margin: 0 0 5px 0;
        }
        .calc-table {
            width: 100%;
            background: transparent !important;
            border: none !important;
            border-collapse: collapse;
        }
        .calc-table th {
            background: #24283b !important;
            color: #7dcfff !important;
            border: none !important;
            text-align: left;
            padding: 10px;
        }
        .calc-table td {
            border: none !important;
            border-bottom: 1px solid #24283b !important;
            padding: 10px;
            color: #c0caf5;
        }
        .calc-unavailable td {
            color: #565f89;
        }
        .calc-btn {
            margin-top: 19px;
            background: #7aa2f7;
            color: #1a1b26;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.2s ease;
        }
        .calc-btn:hover {
            background: #8caaee;
        }
    `;
    document.head.appendChild(style);

    // Initial Layout Setup
    calcContainer.innerHTML = `
        <div class="calc-wrapper">
            <h2>${currentSkill} Calculator</h2>
            <div class="calc-inputs">
                <div class="calc-input-group">
                    <label>Current Level</label>
                    <input type="number" id="calc-current-lvl" value="1" min="1" max="99">
                </div>
                <div class="calc-input-group">
                    <label>Target Level</label>
                    <input type="number" id="calc-target-lvl" value="10" min="2" max="99">
                </div>
                <button class="calc-btn" id="calc-refresh-btn">Calculate</button>
            </div>
            <div id="calc-results"></div>
        </div>
    `;

    document.getElementById('calc-current-lvl').addEventListener('change', renderCalculator);
    document.getElementById('calc-target-lvl').addEventListener('change', renderCalculator);
    document.getElementById('calc-refresh-btn').addEventListener('click', renderCalculator);

    // Render initially
    renderCalculator();
});