MediaWiki:Common.js: Difference between revisions

From Winds Of Valen Wiki
Jump to navigation Jump to search
OSRS Calculator Loader and Reader Mode
Switched to use CSS class for passing arguments
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* OSRS Custom JS Framework */
$(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;
    }


// 1. Asynchronous Calculator Loader
    // Convert level to XP
$(function() {
    function levelToXP(level) {
    if ($('.jcConfig').length > 0) {
        if (level < 1) return xpTable[1];
         // Asynchronously pull in calculator scripts
         if (level > 99) return xpTable[99];
        mw.loader.getScript('/resources/assets/calc.js').then(function() {
         return xpTable[level];
            mw.loader.load('/resources/assets/calc.css', 'text/css');
            console.log("OSRS calculators loaded.");
         });
     }
     }
});


// 2. Reader Mode Toggle
    function calculateActions(currentXP, targetXP) {
$(function() {
        const xpNeeded = targetXP - currentXP;
    var isReaderMode = localStorage.getItem('osrs-reader-mode') === 'true';
        if (xpNeeded <= 0) return [];
   
        return actions.map(action => {
    function toggleReaderMode() {
            const amount = Math.ceil(xpNeeded / action.xp);
        isReaderMode = !isReaderMode;
            return { ...action, amount, xpNeeded };
        localStorage.setItem('osrs-reader-mode', isReaderMode);
         }).sort((a, b) => a.reqLevel - b.reqLevel);
         $('body').toggleClass('reader-mode-active', isReaderMode);
     }
     }
      
 
    if (isReaderMode) {
     function renderCalculator() {
         $('body').addClass('reader-mode-active');
        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;
     }
     }
      
 
     // Insert toggle button into personal nav
    // Inject CSS
     var btn = $('<li><a href="#" id="pt-reader-mode">Toggle Reader Mode</a></li>');
     const style = document.createElement('style');
     btn.on('click', function(e) {
    style.innerHTML = `
        e.preventDefault();
        .calc-wrapper {
        toggleReaderMode();
            background: #1a1b26;
    });
            color: #a9b1d6;
     $('#p-personal ul').prepend(btn);
            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();
});
});

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();
});