MediaWiki:Common.js: Difference between revisions
Automated page publish |
gave the mobile menu some actual links |
||
| (14 intermediate revisions by the same user not shown) | |||
| Line 4: | Line 4: | ||
$('#ca-view a').text('Read'); | $('#ca-view a').text('Read'); | ||
}); | }); | ||
// ========================================================================== | |||
// Minerva (mobile skin) main menu only ships Home/Random by default; it does | |||
// not pull in MediaWiki:Sidebar the way Vector's portlets do. This injects | |||
// the same section links (kept in sync with MediaWiki:Sidebar by hand) into | |||
// the native menu markup so mobile visitors actually get real navigation | |||
// instead of just Home/Random/Settings/About/Disclaimers. | |||
(function () { | |||
function initMinervaNav() { | |||
try { | |||
if (!document.body || !document.body.classList.contains('skin-minerva')) return; | |||
var nav = document.getElementById('p-navigation'); | |||
if (!nav || document.getElementById('wov-minerva-extra-nav')) return; | |||
var sections = [ | |||
{ heading: 'Guides', items: [ | |||
['Getting started', '/w/Getting_Started'], | |||
['Interactive Map (Fullscreen)', 'https://jxlife.github.io/WindsOfValenMap/'], | |||
['All skills', '/w/Skills'], | |||
['All quests', '/w/Quests'], | |||
['Combat guide', '/w/Combat'] | |||
]}, | |||
{ heading: 'Database', items: [ | |||
['Item database', '/w/Items'], | |||
['NPC database', '/w/NPCs'], | |||
['Set bonuses', '/w/Set_bonuses'] | |||
]}, | |||
{ heading: 'Skills', items: [ | |||
['Skill Calculator', '/w/Calculators'], | |||
['Mining', '/w/Mining'], | |||
['Smithing', '/w/Smithing'], | |||
['Fishing', '/w/Fishing'], | |||
['Potion Making', '/w/Potion_Making'] | |||
]}, | |||
{ heading: 'Tools', items: [ | |||
['About this wiki', '/w/Project:About'], | |||
['Random page', '/w/Special:Random'], | |||
['New files', '/w/Special:NewFiles'], | |||
['Wanted pages', '/w/Special:WantedPages'], | |||
['Wiki statistics', '/w/Special:Statistics'] | |||
]}, | |||
{ heading: 'Updates', items: [ | |||
['Recent changes', '/w/Special:RecentChanges'] | |||
]} | |||
]; | |||
var container = document.createElement('div'); | |||
container.id = 'wov-minerva-extra-nav'; | |||
sections.forEach(function (section) { | |||
var heading = document.createElement('div'); | |||
heading.className = 'wov-minerva-nav-heading'; | |||
heading.textContent = section.heading; | |||
container.appendChild(heading); | |||
var ul = document.createElement('ul'); | |||
ul.className = 'toggle-list__list'; | |||
section.items.forEach(function (item) { | |||
var li = document.createElement('li'); | |||
li.className = 'toggle-list-item'; | |||
var a = document.createElement('a'); | |||
a.className = 'toggle-list-item__anchor'; | |||
a.href = item[1]; | |||
var label = document.createElement('span'); | |||
label.className = 'toggle-list-item__label'; | |||
label.textContent = item[0]; | |||
a.appendChild(label); | |||
li.appendChild(a); | |||
ul.appendChild(li); | |||
}); | |||
container.appendChild(ul); | |||
}); | |||
nav.parentNode.insertBefore(container, nav.nextSibling); | |||
} catch (e) {} | |||
} | |||
if (document.body) { | |||
initMinervaNav(); | |||
} else { | |||
document.addEventListener('DOMContentLoaded', initMinervaNav); | |||
} | |||
})(); | |||
// ========================================================================== | // ========================================================================== | ||
// Valen Ledger — Gathering & Combat XP Calculator | // Valen Ledger — Gathering & Combat XP Calculator | ||
| Line 24: | Line 106: | ||
fishing: [ {name:'Minnow',xp:8},{name:'Blue Gill',xp:75},{name:'Common Trout',xp:75},{name:'Bass',xp:200},{name:'Perch',xp:225},{name:'Elder Trout',xp:500},{name:'Carp',xp:1250} ], | fishing: [ {name:'Minnow',xp:8},{name:'Blue Gill',xp:75},{name:'Common Trout',xp:75},{name:'Bass',xp:200},{name:'Perch',xp:225},{name:'Elder Trout',xp:500},{name:'Carp',xp:1250} ], | ||
mining: [ {name:'Copper',xp:15},{name:'Tin',xp:15},{name:'Iron',xp:30},{name:'Coal',xp:80},{name:'Mithril',xp:150},{name:'Silver',xp:300},{name:'Gold',xp:350},{name:'Essence',xp:550} ], | mining: [ {name:'Copper',xp:15},{name:'Tin',xp:15},{name:'Iron',xp:30},{name:'Coal',xp:80},{name:'Mithril',xp:150},{name:'Silver',xp:300},{name:'Gold',xp:350},{name:'Essence',xp:550} ], | ||
smithing: [ {name:'Iron Rod',xp:10},{name:' | smithing: [ | ||
// Bronze | |||
{name:'Bronze Bar',xp:15},{name:'Bronze Helmet',xp:60},{name:'Bronze Platebody',xp:60},{name:'Bronze Platelegs',xp:120},{name:'Bronze Sword',xp:90}, | |||
// Iron | |||
{name:'Iron Bar',xp:30},{name:'Iron Rod',xp:10},{name:'Iron Plate',xp:30},{name:'Iron Helmet',xp:120},{name:'Iron Platebody',xp:300},{name:'Iron Platelegs',xp:240},{name:'Iron Sword',xp:180}, | |||
// Steel | |||
{name:'Steel Bar',xp:55},{name:'Steel Rod',xp:30},{name:'Large Steel Rod',xp:40},{name:'Steel Plate',xp:60},{name:'Large Steel Plate',xp:70},{name:'Steel Helmet',xp:220},{name:'Steel Platebody',xp:550},{name:'Steel Platelegs',xp:440},{name:'Steel Sword',xp:330}, | |||
// Mithril | |||
{name:'Mithril Bar',xp:155},{name:'Large Mithril Rod',xp:275},{name:'Mithril Rod',xp:250},{name:'Large Mithril Plate',xp:550},{name:'Mithril Plate',xp:500},{name:'Mithril Helmet',xp:620},{name:'Mithril Platebody',xp:1550},{name:'Mithril Platelegs',xp:1240},{name:'Mithril Sword',xp:930}, | |||
// Silver | |||
{name:'Silver Bar',xp:675},{name:'Silver Plate',xp:400},{name:'Silver Foil',xp:400}, | |||
// Gold | |||
{name:'Gold Bar',xp:800},{name:'Gold Plate',xp:400},{name:'Golden Shield Frame',xp:1000}, | |||
// Ebony | |||
{name:'Ebony Bar',xp:1800},{name:'Small Ebony Rod',xp:3000},{name:'Large Ebony Rod',xp:3500},{name:'Ebony Rod',xp:3250},{name:'Small Ebony Plate',xp:6000},{name:'Ebony Plate',xp:6500},{name:'Large Ebony Plate',xp:7000}, | |||
// Duskknight | |||
{name:'Duskknight Boot Left Sabaton',xp:10000},{name:'Duskknight Boot Right Sabaton',xp:10000},{name:'Duskknight Leg Tuille',xp:10000},{name:'Duskknight Leg Poleyn',xp:10000},{name:'Duskknight Body Pauldron',xp:10000},{name:'Duskknight Body Couter',xp:10000},{name:'Duskknight Body Rerebrace',xp:12000},{name:'Duskknight Body Vambrace',xp:12000},{name:'Duskknight Leg Tasset',xp:14000},{name:'Duskknight Boot Greave',xp:15000},{name:'Duskknight Leg Cuisses',xp:15000},{name:'Duskknight Helmet Face Plate',xp:15000},{name:'Duskknight Helmet Head Plate',xp:15000},{name:'Duskknight Helmet Spike',xp:15000},{name:'Duskknight Body Breastplate',xp:18000} | |||
], | |||
potionmaking: [ {name:'Fishing Potion',xp:500},{name:'Weak Health Potion',xp:500},{name:'Mining Potion',xp:1000},{name:'Shields Potion',xp:1500},{name:'Normal Health Potion',xp:1500},{name:'Attack Potion',xp:1500},{name:'Archery Potion',xp:1750},{name:'Magic Potion',xp:2000},{name:'Strong Health Potion',xp:3250},{name:'Strong Shields Potion',xp:6000} ] | potionmaking: [ {name:'Fishing Potion',xp:500},{name:'Weak Health Potion',xp:500},{name:'Mining Potion',xp:1000},{name:'Shields Potion',xp:1500},{name:'Normal Health Potion',xp:1500},{name:'Attack Potion',xp:1500},{name:'Archery Potion',xp:1750},{name:'Magic Potion',xp:2000},{name:'Strong Health Potion',xp:3250},{name:'Strong Shields Potion',xp:6000} ] | ||
}; | }; | ||
Object.keys(GATHER).forEach(function(k){ GATHER[k].sort(function(a,b){ return a.xp-b.xp; }); }); | Object.keys(GATHER).forEach(function(k){ if (k === 'smithing') return; GATHER[k].sort(function(a,b){ return a.xp-b.xp; }); }); | ||
// Smithing crafting tree, sourced from the game's own recipe data (not fan-site numbers). | // Smithing crafting tree, sourced from the game's own recipe data (not fan-site numbers). | ||
| Line 69: | Line 168: | ||
'Duskknight Body Breastplate': [{name:'Large Ebony Plate', count:4},{name:'Silver Foil', count:8}], | 'Duskknight Body Breastplate': [{name:'Large Ebony Plate', count:4},{name:'Silver Foil', count:8}], | ||
'Bronze Bar': [{name:'Copper Ore', count:1},{name:'Tin Ore', count:1}], | 'Bronze Bar': [{name:'Copper Ore', count:1},{name:'Tin Ore', count:1}], | ||
'Bronze Helmet': [{name:'Bronze Bar', count:4}], | |||
'Bronze Platebody': [{name:'Bronze Bar', count:10}], | |||
'Bronze Platelegs': [{name:'Bronze Bar', count:8}], | |||
'Bronze Sword': [{name:'Bronze Bar', count:6}], | |||
'Iron Bar': [{name:'Iron Ore', count:2}], | 'Iron Bar': [{name:'Iron Ore', count:2}], | ||
'Iron Helmet': [{name:'Iron Bar', count:4}], | |||
'Iron Platebody': [{name:'Iron Bar', count:10}], | |||
'Iron Platelegs': [{name:'Iron Bar', count:8}], | |||
'Iron Sword': [{name:'Iron Bar', count:6}], | |||
'Steel Bar': [{name:'Iron Ore', count:1},{name:'Coal Ore', count:1}], | 'Steel Bar': [{name:'Iron Ore', count:1},{name:'Coal Ore', count:1}], | ||
'Steel Helmet': [{name:'Steel Bar', count:4}], | |||
'Steel Platebody': [{name:'Steel Bar', count:10}], | |||
'Steel Platelegs': [{name:'Steel Bar', count:8}], | |||
'Steel Sword': [{name:'Steel Bar', count:6}], | |||
'Mithril Bar': [{name:'Mithril Ore', count:1},{name:'Coal Ore', count:2}], | 'Mithril Bar': [{name:'Mithril Ore', count:1},{name:'Coal Ore', count:2}], | ||
'Mithril Helmet': [{name:'Mithril Bar', count:4}], | |||
'Mithril Platebody': [{name:'Mithril Bar', count:10}], | |||
'Mithril Platelegs': [{name:'Mithril Bar', count:8}], | |||
'Mithril Sword': [{name:'Mithril Bar', count:6}], | |||
'Gold Bar': [{name:'Gold Ore', count:8}], | 'Gold Bar': [{name:'Gold Ore', count:8}], | ||
'Silver Bar': [{name:'Silver Ore', count:7}], | 'Silver Bar': [{name:'Silver Ore', count:7}], | ||
| Line 86: | Line 201: | ||
return null; | return null; | ||
} | } | ||
// Seconds per craft at the Anvil/Furnace, one entry per RECIPES key. Bar/Helmet/Platebody/ | |||
// Platelegs/Sword durations for Bronze-Mithril come straight off the Smithing Guide tables; | |||
// everything else comes from the game's own recipe data. | |||
var CRAFT_DURATION = { | |||
'Bronze Bar':3, 'Bronze Helmet':6, 'Bronze Platebody':18, 'Bronze Platelegs':16, 'Bronze Sword':8, | |||
'Iron Bar':4, 'Iron Rod':15, 'Iron Plate':4, 'Iron Helmet':10, 'Iron Platebody':28, 'Iron Platelegs':24, 'Iron Sword':12, | |||
'Steel Bar':5, 'Steel Rod':3, 'Large Steel Rod':3, 'Steel Plate':5, 'Large Steel Plate':5, 'Steel Helmet':14, 'Steel Platebody':38, 'Steel Platelegs':32, 'Steel Sword':16, | |||
'Mithril Bar':6, 'Large Mithril Rod':13, 'Mithril Rod':13, 'Large Mithril Plate':22, 'Mithril Plate':22, 'Mithril Helmet':18, 'Mithril Platebody':48, 'Mithril Platelegs':40, 'Mithril Sword':20, | |||
'Silver Bar':10, 'Silver Plate':15, 'Silver Foil':15, | |||
'Gold Bar':15, 'Gold Plate':15, 'Golden Shield Frame':60, | |||
'Small Ebony Rod':40, 'Large Ebony Rod':40, 'Ebony Rod':40, 'Small Ebony Plate':60, 'Ebony Plate':60, 'Large Ebony Plate':60, 'Ebony Bar':20, | |||
'Duskknight Boot Left Sabaton':120, 'Duskknight Boot Right Sabaton':120, 'Duskknight Leg Tuille':120, 'Duskknight Leg Poleyn':120, 'Duskknight Body Pauldron':120, 'Duskknight Body Couter':120, 'Duskknight Body Rerebrace':120, 'Duskknight Body Vambrace':120, 'Duskknight Leg Tasset':120, 'Duskknight Boot Greave':120, 'Duskknight Leg Cuisses':120, 'Duskknight Helmet Face Plate':120, 'Duskknight Helmet Head Plate':120, 'Duskknight Helmet Spike':120, 'Duskknight Body Breastplate':120 | |||
}; | |||
// Walks RECIPES tier-by-tier from `qty` of `name`, merging same-name items within a tier. | // Walks RECIPES tier-by-tier from `qty` of `name`, merging same-name items within a tier. | ||
| Line 346: | Line 475: | ||
if (rawNames.length){ | if (rawNames.length){ | ||
text += '\n\nTotal raw materials: ' + rawNames.map(function(n){ return fmt(breakdown.totals[n]) + ' ' + n; }).join(', '); | text += '\n\nTotal raw materials: ' + rawNames.map(function(n){ return fmt(breakdown.totals[n]) + ' ' + n; }).join(', '); | ||
} | |||
var totalSeconds = breakdown.entries.reduce(function(sum, e){ | |||
var dur = CRAFT_DURATION[e.name]; | |||
return dur ? sum + e.qty * dur : sum; | |||
}, 0); | |||
if (totalSeconds > 0){ | |||
text += '\nTotal craft time (Anvil/Furnace only, not counting ore gathering): ' + formatTime(totalSeconds); | |||
} | } | ||
breakdownText.textContent = text; | breakdownText.textContent = text; | ||
| Line 762: | Line 898: | ||
selectTab('fishing'); | selectTab('fishing'); | ||
}); | }); | ||
// ========================================================================== | |||
// Mobile nav toggle — the sidebar (#mw-panel) renders inline far down the | |||
// page on narrow screens, so add a fixed hamburger button that slides it in | |||
// as an overlay drawer instead. CSS in Common.css keeps this hidden/inert | |||
// on desktop widths (>=1000px). | |||
// ========================================================================== | |||
(function () { | |||
function initMobileNav() { | |||
var panel = document.getElementById('mw-panel'); | |||
if (!panel || document.getElementById('mobile-nav-toggle')) return; | |||
var toggle = document.createElement('button'); | |||
toggle.id = 'mobile-nav-toggle'; | |||
toggle.type = 'button'; | |||
toggle.setAttribute('aria-label', 'Toggle navigation menu'); | |||
toggle.textContent = '\u2630 Menu'; | |||
var backdrop = document.createElement('div'); | |||
backdrop.id = 'mobile-nav-backdrop'; | |||
document.body.insertBefore(backdrop, document.body.firstChild); | |||
document.body.insertBefore(toggle, document.body.firstChild); | |||
function closeNav() { | |||
panel.classList.remove('mobile-nav-open'); | |||
backdrop.classList.remove('mobile-nav-open'); | |||
} | |||
function toggleNav() { | |||
panel.classList.toggle('mobile-nav-open'); | |||
backdrop.classList.toggle('mobile-nav-open'); | |||
} | |||
toggle.addEventListener('click', toggleNav); | |||
backdrop.addEventListener('click', closeNav); | |||
panel.querySelectorAll('a').forEach(function (a) { | |||
a.addEventListener('click', closeNav); | |||
}); | |||
} | |||
if (document.readyState === 'loading') { | |||
document.addEventListener('DOMContentLoaded', initMobileNav); | |||
} else { | |||
initMobileNav(); | |||
} | |||
})(); | |||