MediaWiki:Common.js: Difference between revisions

Add simple image lightbox
Switched to use CSS class for passing arguments
 
(4 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';


// 1. Asynchronous Calculator Loader
    const skillClass = Array.from(calcContainer.classList).find(c => c.startsWith('skill-'));
$(function() {
    if (!skillClass) {
    if ($('.jcConfig').length > 0) {
        calcContainer.innerHTML = "<p style='color:red;'>Error: No skill class found on container.</p>";
        // Asynchronously pull in calculator scripts
         return;
        mw.loader.getScript('/resources/assets/calc.js').then(function() {
            mw.loader.load('/resources/assets/calc.css', 'text/css');
            console.log("OSRS calculators loaded.");
         });
     }
     }
});
    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
    ];


// 2. Reader Mode Toggle
    // Data compiled from the scraped files
$(function() {
    const skillData = {
     var isReaderMode = localStorage.getItem('osrs-reader-mode') === 'true';
        "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 }
        ]
     };


     function applyReaderMode() {
     const actions = skillData[currentSkill];
         $('body').toggleClass('reader-mode-active', isReaderMode);
    if (!actions) {
         $('#reader-mode-escape').toggle(isReaderMode);
         calcContainer.innerHTML = "<p style='color:red;'>Calculator data not found for " + currentSkill + ".</p>";
         return;
     }
     }


     function toggleReaderMode() {
    // Convert level to XP
         isReaderMode = !isReaderMode;
     function levelToXP(level) {
         localStorage.setItem('osrs-reader-mode', String(isReaderMode));
         if (level < 1) return xpTable[1];
         applyReaderMode();
         if (level > 99) return xpTable[99];
         return xpTable[level];
     }
     }


     // Insert toggle button into personal nav (in the header)
     function calculateActions(currentXP, targetXP) {
    var btn = $('<li><a href="#" id="pt-reader-mode">Toggle Reader Mode</a></li>');
        const xpNeeded = targetXP - currentXP;
    btn.on('click', function(e) {
        if (xpNeeded <= 0) return [];
        e.preventDefault();
        return actions.map(action => {
        toggleReaderMode();
            const amount = Math.ceil(xpNeeded / action.xp);
    });
            return { ...action, amount, xpNeeded };
    $('#p-personal ul').prepend(btn);
        }).sort((a, b) => a.reqLevel - b.reqLevel);
    }


     // Also inject a fixed escape button that is ALWAYS visible in reader mode
     function renderCalculator() {
    var escapeBtn = $('<div id="reader-mode-escape" style="' +
         const currentLvl = parseInt(document.getElementById('calc-current-lvl').value) || 1;
         'display:none; position:fixed; top:10px; left:10px; z-index:99999;' +
         const targetLvl = parseInt(document.getElementById('calc-target-lvl').value) || (currentLvl + 1);
        'background:rgba(0,0,0,0.7); color:#fff; padding:8px 14px;' +
        'border-radius:6px; cursor:pointer; font-size:13px; font-weight:bold;' +
        'box-shadow:0 2px 8px rgba(0,0,0,0.4);">&#x2715; Exit Reader Mode</div>');
    escapeBtn.on('click', function() {
         toggleReaderMode();
    });
    $('body').append(escapeBtn);


    // Apply state on page load
        const currentXP = levelToXP(currentLvl);
    applyReaderMode();
        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;
    }


// 3. Simple Image Lightbox
    // Inject CSS
$(function() {
     const style = document.createElement('style');
     $('a.image').on('click', function(e) {
    style.innerHTML = `
        e.preventDefault();
         .calc-wrapper {
       
             background: #1a1b26;
        var imgUrl = $(this).attr('href');
            color: #a9b1d6;
         if ($(this).find('img').length > 0) {
             padding: 20px;
             // Get original image url by stripping /thumb/ and the filename at the end
             border-radius: 8px;
             var thumbSrc = $(this).find('img').attr('src');
            border: 1px solid #414868;
             if (thumbSrc.indexOf('/images/thumb/') !== -1) {
            max-width: 600px;
                var parts = thumbSrc.split('/');
            margin: 20px 0;
                parts.pop(); // remove the scaled filename like 300px-Scouts.png
            font-family: 'Inter', sans-serif;
                imgUrl = parts.join('/').replace('/images/thumb/', '/images/');
             box-shadow: 0 10px 25px rgba(0,0,0,0.5);
             } else {
                imgUrl = thumbSrc;
            }
         }
         }
          
         .calc-wrapper h2 {
        var overlay = $('<div id="osrs-lightbox" style="position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.85); z-index:999999; display:flex; align-items:center; justify-content:center; cursor:pointer;"></div>');
            margin-top: 0;
         var img = $('<img src="' + imgUrl + '" style="max-width:95%; max-height:95%; box-shadow:0 0 20px rgba(0,0,0,0.8); border:2px solid #b3a07d;" />');
            color: #7aa2f7;
          
            border-bottom: 2px solid #24283b;
         var loading = $('<div style="color:white; font-family:sans-serif; position:absolute;">Loading...</div>');
            padding-bottom: 10px;
         overlay.append(loading);
        }
          
        .calc-inputs {
         img.on('load', function() {
            display: flex;
             loading.remove();
            gap: 20px;
         });
            margin-bottom: 20px;
          
        }
        overlay.append(img);
        .calc-input-group {
       
            display: flex;
         overlay.on('click', function() {
            flex-direction: column;
             $(this).fadeOut(200, function() {
            gap: 5px;
                 $(this).remove();
        }
            });
        .calc-input-group label {
        });
            font-size: 12px;
       
            text-transform: uppercase;
        $('body').append(overlay);
            font-weight: bold;
        overlay.hide().fadeIn(200);
            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();
});
});