Common.js: Difference between revisions
From Dune Awakening DB
mNo edit summary |
mNo edit summary |
||
| Line 183: | Line 183: | ||
/* ===== Used-In | /* ===== Used-In dynamic filters & search ===== */ | ||
mw.hook('wikipage.content').add(function ( $content ) { | mw.hook( 'wikipage.content' ).add( function ( $content ) { | ||
const $holder = $content.find( '#usedInFilterHolder' ); | |||
const $table = $content.find( '#usedInTable' ); | |||
if ( !$holder.length || !$table.length ) return; | |||
// | /* ---------- harvest meta from rows once ---------- */ | ||
const rowsData = []; | |||
const stations = new Set(); | |||
const types = new Set(); | |||
$.each( | $table.find( 'tbody tr' ).each( function () { | ||
const $tds = $( this ).children( 'td' ); | |||
const output = $tds.eq( 0 ).text().trim(); | |||
const type = $tds.eq( 1 ).text().trim(); // comment out if not needed | |||
const station = $tds.last().text().trim(); | |||
rowsData.push( { tr: this, output, type, station } ); | |||
stations.add( station ); | |||
types.add( type ); | |||
} ); | |||
// | /* ---------- build UI ---------- */ | ||
$sel. | const makeSel = ( id, label, opts ) => { | ||
const $sel = $( '<select>', { id, class: 'game-button', css:{margin:'6px 4px 6px 0'} } ) | |||
.append( $( '<option>', { value:'', text:label } ) ); | |||
opts.forEach( o => $sel.append( $( '<option>', { value:o, text:o } ) ) ); | |||
return $sel; | |||
}); | }; | ||
}); | |||
}); | const $stationSel = makeSel( 'filterStation', 'All Stations', [ ...stations ].sort() ); | ||
const $typeSel = makeSel( 'filterType', 'All Types', [ ...types ].sort() ); // remove if unused | |||
const $search = $( '<input>', { | |||
type:'text', | |||
placeholder:'Search…', | |||
css:{ margin:'6px 0', padding:'4px', width:'140px', | |||
'background':'#111', color:'#fff', border:'1px solid #555' } | |||
} ); | |||
$holder.append( $stationSel, $typeSel, $search ); // drop $typeSel if not wanted | |||
/* ---------- filter engine (runs on any change) ---------- */ | |||
function applyFilters() { | |||
const sVal = $stationSel.val(); | |||
const tVal = $typeSel.val(); | |||
const q = $search.val().toLowerCase(); | |||
rowsData.forEach( ({ tr, output, type, station }) => { | |||
const show = | |||
(!sVal || station === sVal) && | |||
(!tVal || type === tVal) && | |||
(!q || output.toLowerCase().includes( q )); | |||
tr.style.display = show ? '' : 'none'; | |||
} ); | |||
} | |||
$stationSel.on( 'change', applyFilters ); | |||
$typeSel .on( 'change', applyFilters ); // remove if you removed $typeSel | |||
$search .on( 'input', applyFilters ); | |||
} ); | |||
Revision as of 02:06, 15 May 2025
// ✅ Radial Menu Loader (Final Version with JSON-in-Div)
function waitForRadialData(callback, attempts = 0) {
const dataTag = document.getElementById('radialMenuData');
if (dataTag) {
try {
const menuItems = JSON.parse(dataTag.innerText || dataTag.textContent);
console.log("✅ Loaded radialMenuData:", menuItems);
callback(menuItems);
} catch (e) {
console.error("❌ Failed to parse radialMenuData", e);
}
} else if (attempts < 20) {
setTimeout(() => waitForRadialData(callback, attempts + 1), 100);
} else {
console.warn("⚠️ radialMenuData tag not found after timeout.");
}
}
$(document).ready(function () {
waitForRadialData(function (menuItems) {
const isMobile = () => window.innerWidth <= 768;
let radialItemsHTML = '';
menuItems.forEach((item, index) => {
const id = item.category.toLowerCase().replace(/\s+/g, '-');
item.id = id;
radialItemsHTML += `
<div class="dune-radial-item-container ${item.position}">
<a data-id="${id}" class="dune-radial-item">
<img src="${item.icon}" alt="${item.name}" class="dune-radial-icon">
<span class="dune-radial-tooltip">${item.name}</span>
</a>
</div>
`;
});
const centerButtonHTML = `
<a href="https://dunedb.com/Main_Page" class="dune-radial-center">
<img src="https://dunedb.com/images/9/99/HomeNavIcon.png" alt="Home" class="dune-radial-icon">
<span class="dune-radial-tooltip">Main Page</span>
</a>
`;
const radialMenuHTML = `
<div id="duneRadialMenu" class="dune-radial-menu">
<div class="dune-radial-background">
<div class="dune-radial-circle outer"></div>
<div class="dune-radial-circle middle"></div>
<div class="dune-radial-circle inner"></div>
</div>
${centerButtonHTML}
${radialItemsHTML}
</div>
<div id="duneRadialOverlay" class="dune-radial-overlay"></div>
`;
const subcategoryContainerHTML = `<div id="duneSubcategoryContainer" class="dune-subcategory-container"></div>`;
$('body').append(radialMenuHTML);
$('body').append(subcategoryContainerHTML);
if (isMobile()) {
$('#duneRadialMenu').addClass('mobile-grid');
}
const showSubcategories = (itemId, event) => {
const item = menuItems.find(i => i.id === itemId);
if (!item || !item.subcategories) return;
$('.dune-radial-item').removeClass('selected');
$(`.dune-radial-item[data-id="${itemId}"]`).addClass('selected');
let subcategoryHTML = `
<div class="dune-subcategory-header">
<img src="${item.icon}" alt="${item.name}" class="dune-subcategory-icon">
<span>${item.name}</span>
</div>
<div class="dune-subcategory-items">
`;
item.subcategories.forEach((sub, index) => {
subcategoryHTML += `
<a href="${sub.url}" class="dune-subcategory-item" style="--item-index: ${index}">
<span class="dune-subcategory-name">${sub.name}</span>
</a>
`;
});
subcategoryHTML += `
</div>
<div class="dune-subcategory-footer">
<a href="${item.url}" class="dune-subcategory-all">View All ${item.name}</a>
</div>
`;
const $subcategoryContainer = $('#duneSubcategoryContainer');
$subcategoryContainer.html(subcategoryHTML);
$subcategoryContainer.removeClass((index, className) => {
return (className.match(/from-\S+/g) || []).join(' ');
});
$subcategoryContainer.addClass(`from-${item.position}`);
$subcategoryContainer.addClass('active');
event.stopPropagation();
};
const hideSubcategories = () => {
$('#duneSubcategoryContainer').removeClass('active');
$('.dune-radial-item').removeClass('selected');
};
const toggleRadialMenu = () => {
if ($('#duneRadialMenu').hasClass('active')) {
hideSubcategories();
$('#duneRadialMenu').removeClass('active');
$('#duneRadialOverlay').removeClass('active');
} else {
$('#duneRadialMenu').addClass('active');
$('#duneRadialOverlay').addClass('active');
$('.dune-radial-item-container').each(function (index) {
const $item = $(this);
setTimeout(() => {
$item.addClass('animated');
}, index * 50);
});
setTimeout(() => {
$('.dune-radial-center').addClass('animated');
}, menuItems.length * 50);
}
};
// ✅ Listen for clicks on both the original logo and the custom menu image inside the wrapper span
$(document).on('click', '#duneLogoBtn, #menuRadialTrigger img', function (e) {
console.log("✅ Radial trigger clicked");
e.preventDefault();
e.stopPropagation();
toggleRadialMenu();
});
$(document).on('click', '.dune-radial-item', function (e) {
e.preventDefault();
e.stopPropagation();
const itemId = $(this).data('id');
if ($(this).hasClass('selected')) {
hideSubcategories();
} else {
showSubcategories(itemId, e);
}
});
$(document).on('click', '#duneRadialOverlay', function () {
hideSubcategories();
$('#duneRadialMenu').removeClass('active');
$('#duneRadialOverlay').removeClass('active');
});
$(document).on('click', 'li.name.logo a[href="/Main_Page"]', function (e) {
e.preventDefault();
toggleRadialMenu();
});
$(document).on('keydown', function (e) {
if (e.key === 'Escape') {
if ($('#duneSubcategoryContainer').hasClass('active')) {
hideSubcategories();
} else if ($('#duneRadialMenu').hasClass('active')) {
$('#duneRadialMenu').removeClass('active');
$('#duneRadialOverlay').removeClass('active');
}
}
});
$(window).on('resize', function () {
if (isMobile()) {
$('#duneRadialMenu').addClass('mobile-grid');
} else {
$('#duneRadialMenu').removeClass('mobile-grid');
}
});
});
});
/* ===== Used-In dynamic filters & search ===== */
mw.hook( 'wikipage.content' ).add( function ( $content ) {
const $holder = $content.find( '#usedInFilterHolder' );
const $table = $content.find( '#usedInTable' );
if ( !$holder.length || !$table.length ) return;
/* ---------- harvest meta from rows once ---------- */
const rowsData = [];
const stations = new Set();
const types = new Set();
$table.find( 'tbody tr' ).each( function () {
const $tds = $( this ).children( 'td' );
const output = $tds.eq( 0 ).text().trim();
const type = $tds.eq( 1 ).text().trim(); // comment out if not needed
const station = $tds.last().text().trim();
rowsData.push( { tr: this, output, type, station } );
stations.add( station );
types.add( type );
} );
/* ---------- build UI ---------- */
const makeSel = ( id, label, opts ) => {
const $sel = $( '<select>', { id, class: 'game-button', css:{margin:'6px 4px 6px 0'} } )
.append( $( '<option>', { value:'', text:label } ) );
opts.forEach( o => $sel.append( $( '<option>', { value:o, text:o } ) ) );
return $sel;
};
const $stationSel = makeSel( 'filterStation', 'All Stations', [ ...stations ].sort() );
const $typeSel = makeSel( 'filterType', 'All Types', [ ...types ].sort() ); // remove if unused
const $search = $( '<input>', {
type:'text',
placeholder:'Search…',
css:{ margin:'6px 0', padding:'4px', width:'140px',
'background':'#111', color:'#fff', border:'1px solid #555' }
} );
$holder.append( $stationSel, $typeSel, $search ); // drop $typeSel if not wanted
/* ---------- filter engine (runs on any change) ---------- */
function applyFilters() {
const sVal = $stationSel.val();
const tVal = $typeSel.val();
const q = $search.val().toLowerCase();
rowsData.forEach( ({ tr, output, type, station }) => {
const show =
(!sVal || station === sVal) &&
(!tVal || type === tVal) &&
(!q || output.toLowerCase().includes( q ));
tr.style.display = show ? '' : 'none';
} );
}
$stationSel.on( 'change', applyFilters );
$typeSel .on( 'change', applyFilters ); // remove if you removed $typeSel
$search .on( 'input', applyFilters );
} );