MediaWiki:Citizen.js: Difference between revisions
MediaWiki interface page
More actions
Joeeasterly (talk | contribs) No edit summary |
Joeeasterly (talk | contribs) No edit summary |
||
| Line 1: | Line 1: | ||
/** | /** | ||
* Dashboard Quick-Jump ( | * Dashboard Quick-Jump (v5 - ES5 Compatible) | ||
* Listens for typing on the Dashboard page and jumps to matching cards. | * Listens for typing on the Dashboard page and jumps to matching cards. | ||
* | * Replaced modern syntax to appease the MediaWiki ResourceLoader gods. | ||
*/ | */ | ||
$(function() { | $(function() { | ||
try { | try { | ||
// 1. EDIT MODE GUARD (URL Check) | // 1. EDIT MODE GUARD (URL Check) | ||
// | // Check if we are trying to edit. | ||
var search = window.location.search; | |||
if ( | if (search.indexOf('veaction') !== -1) return; | ||
if ( | if (search.indexOf('action=edit') !== -1) return; | ||
if ( | if (search.indexOf('action=submit') !== -1) return; | ||
// 2. CONTEXT GUARD | // 2. CONTEXT GUARD | ||
// If there are no dashboard cards, exit. | // If there are no dashboard cards, exit. | ||
var cards = document.querySelectorAll('.dashboard-card'); | |||
if (cards.length === 0) return; | |||
var CONFIG = { | |||
selectorCard: '.dashboard-card', | selectorCard: '.dashboard-card', | ||
selectorLabel: '.dashboard-label', | selectorLabel: '.dashboard-label', | ||
| Line 26: | Line 27: | ||
}; | }; | ||
var searchBuffer = ''; | |||
var clearTimer = null; | |||
document.addEventListener('keydown', function(e) { | document.addEventListener('keydown', function(e) { | ||
// 3. EDIT INTERFACE GUARD (Dynamic) | // 3. EDIT INTERFACE GUARD (Dynamic) | ||
// | // Check for active editor classes or elements | ||
if (document.documentElement.classList.contains('ve-active') || | if (document.documentElement.classList.contains('ve-active') || | ||
document.querySelector('.ve-ui-surface') || | document.querySelector('.ve-ui-surface') || | ||
| Line 40: | Line 41: | ||
// 4. INPUT GUARD | // 4. INPUT GUARD | ||
// Don't intercept typing in search bars or inputs | // Don't intercept typing in search bars or inputs | ||
var target = e.target; | |||
if ( | var tagName = target.tagName; | ||
if (tagName === 'INPUT' || | |||
tagName === 'TEXTAREA' || | |||
tagName === 'SELECT' || | |||
target.isContentEditable) { | target.isContentEditable) { | ||
return; | return; | ||
| Line 59: | Line 61: | ||
if (e.key === 'Enter') { | if (e.key === 'Enter') { | ||
var active = document.querySelector('.' + CONFIG.classActive + ' ' + CONFIG.selectorLink); | |||
if (active) { | if (active) { | ||
e.preventDefault(); | e.preventDefault(); | ||
| Line 87: | Line 89: | ||
function updateSelection() { | function updateSelection() { | ||
// Clear previous highlights | // Clear previous highlights | ||
document.querySelectorAll( | var actives = document.querySelectorAll('.' + CONFIG.classActive); | ||
for (var i = 0; i < actives.length; i++) { | |||
actives[i].classList.remove(CONFIG.classActive); | |||
} | |||
if (!searchBuffer) return; | if (!searchBuffer) return; | ||
// Escape special regex chars | |||
// Escape special regex chars | var safeBuffer = searchBuffer.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); | ||
var regex = new RegExp('^' + safeBuffer, 'i'); | |||
for ( | for (var j = 0; j < cards.length; j++) { | ||
var card = cards[j]; | |||
var labelEl = card.querySelector(CONFIG.selectorLabel); | |||
var descEl = card.querySelector(CONFIG.selectorDesc); | |||
// Old school null checks (No optional chaining ?.) | |||
var label = labelEl ? labelEl.innerText.trim() : ''; | |||
var desc = descEl ? descEl.innerText.trim() : ''; | |||
// Priority 1: Label match | // Priority 1: Label match | ||
| Line 120: | Line 129: | ||
function resetSearch() { | function resetSearch() { | ||
searchBuffer = ''; | searchBuffer = ''; | ||
document.querySelectorAll( | var actives = document.querySelectorAll('.' + CONFIG.classActive); | ||
for (var i = 0; i < actives.length; i++) { | |||
actives[i].classList.remove(CONFIG.classActive); | |||
} | |||
} | } | ||
Revision as of 00:22, 2 February 2026
/**
* Dashboard Quick-Jump (v5 - ES5 Compatible)
* Listens for typing on the Dashboard page and jumps to matching cards.
* Replaced modern syntax to appease the MediaWiki ResourceLoader gods.
*/
$(function() {
try {
// 1. EDIT MODE GUARD (URL Check)
// Check if we are trying to edit.
var search = window.location.search;
if (search.indexOf('veaction') !== -1) return;
if (search.indexOf('action=edit') !== -1) return;
if (search.indexOf('action=submit') !== -1) return;
// 2. CONTEXT GUARD
// If there are no dashboard cards, exit.
var cards = document.querySelectorAll('.dashboard-card');
if (cards.length === 0) return;
var CONFIG = {
selectorCard: '.dashboard-card',
selectorLabel: '.dashboard-label',
selectorDesc: '.dashboard-desc',
selectorLink: 'a',
classActive: 'dashboard-jump-active',
timeout: 1500
};
var searchBuffer = '';
var clearTimer = null;
document.addEventListener('keydown', function(e) {
// 3. EDIT INTERFACE GUARD (Dynamic)
// Check for active editor classes or elements
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
var target = e.target;
var tagName = target.tagName;
if (tagName === 'INPUT' ||
tagName === 'TEXTAREA' ||
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') {
var 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
var actives = document.querySelectorAll('.' + CONFIG.classActive);
for (var i = 0; i < actives.length; i++) {
actives[i].classList.remove(CONFIG.classActive);
}
if (!searchBuffer) return;
// Escape special regex chars
var safeBuffer = searchBuffer.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
var regex = new RegExp('^' + safeBuffer, 'i');
for (var j = 0; j < cards.length; j++) {
var card = cards[j];
var labelEl = card.querySelector(CONFIG.selectorLabel);
var descEl = card.querySelector(CONFIG.selectorDesc);
// Old school null checks (No optional chaining ?.)
var label = labelEl ? labelEl.innerText.trim() : '';
var desc = descEl ? descEl.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 = '';
var actives = document.querySelectorAll('.' + CONFIG.classActive);
for (var i = 0; i < actives.length; i++) {
actives[i].classList.remove(CONFIG.classActive);
}
}
} catch (err) {
console.error('Hallyu Dashboard Script Error:', err);
}
});