MediaWiki:Citizen.js
MediaWiki interface page
More actions
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* Dashboard Quick-Jump (v4 - Bulletproof)
* Listens for typing on the Dashboard page and jumps to matching cards.
* Wrapped in strict safety guards to prevent breaking the editor.
*/
$(function() { // Wait for the DOM to be fully ready
try {
// 1. EDIT MODE GUARD (URL Check)
// If the URL contains 'veaction' (VisualEditor) or 'action=edit', stop immediately.
// We use simple string checking here for maximum compatibility.
if (window.location.search.indexOf('veaction') !== -1) return;
if (window.location.search.indexOf('action=edit') !== -1) return;
if (window.location.search.indexOf('action=submit') !== -1) return;
// 2. CONTEXT GUARD
// If there are no dashboard cards, exit.
if (!document.querySelector('.dashboard-card')) return;
const CONFIG = {
selectorCard: '.dashboard-card',
selectorLabel: '.dashboard-label',
selectorDesc: '.dashboard-desc',
selectorLink: 'a',
classActive: 'dashboard-jump-active',
timeout: 1500
};
let searchBuffer = '';
let clearTimer = null;
document.addEventListener('keydown', function(e) {
// 3. EDIT INTERFACE GUARD (Dynamic)
// Even if the URL looked safe, check if an editor overlay is actually open.
if (document.documentElement.classList.contains('ve-active') ||
document.querySelector('.ve-ui-surface') ||
document.querySelector('.wikiEditor-ui')) {
return;
}
// 4. INPUT GUARD
// Don't intercept typing in search bars or inputs
const target = e.target;
if (target.tagName === 'INPUT' ||
target.tagName === 'TEXTAREA' ||
target.tagName === 'SELECT' ||
target.isContentEditable) {
return;
}
// 5. MODIFIER GUARD
if (e.ctrlKey || e.altKey || e.metaKey) return;
// --- Logic ---
if (e.key === 'Escape') {
resetSearch();
return;
}
if (e.key === 'Enter') {
const active = document.querySelector(`.${CONFIG.classActive} ${CONFIG.selectorLink}`);
if (active) {
e.preventDefault();
e.stopPropagation();
active.click();
}
return;
}
if (e.key === 'Backspace') {
searchBuffer = searchBuffer.slice(0, -1);
if (searchBuffer.length === 0) resetSearch();
else updateSelection();
return;
}
// Capture single char keys (letters/numbers)
if (e.key.length === 1) {
searchBuffer += e.key;
updateSelection();
clearTimeout(clearTimer);
clearTimer = setTimeout(resetSearch, CONFIG.timeout);
}
});
function updateSelection() {
// Clear previous highlights
document.querySelectorAll(`.${CONFIG.classActive}`).forEach(el => el.classList.remove(CONFIG.classActive));
if (!searchBuffer) return;
const cards = document.querySelectorAll(CONFIG.selectorCard);
// Escape special regex chars to avoid crashes
const safeBuffer = searchBuffer.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(`^${safeBuffer}`, 'i');
for (const card of cards) {
const label = card.querySelector(CONFIG.selectorLabel)?.innerText.trim() || '';
const desc = card.querySelector(CONFIG.selectorDesc)?.innerText.trim() || '';
// Priority 1: Label match
if (label && regex.test(label)) {
activateCard(card);
return;
}
// Priority 2: Description match
if (desc && regex.test(desc)) {
activateCard(card);
return;
}
}
}
function activateCard(card) {
card.classList.add(CONFIG.classActive);
card.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
function resetSearch() {
searchBuffer = '';
document.querySelectorAll(`.${CONFIG.classActive}`).forEach(el => el.classList.remove(CONFIG.classActive));
}
} catch (err) {
console.error('Hallyu Dashboard Script Error:', err);
}
});