MediaWiki:Common.js: различия между версиями
Удаление старой попытки кастомного поиска Метка: ручная отмена |
Постоянный поиск в верхней панели Citizen |
||
| Строка 140: | Строка 140: | ||
window.setInterval(updateStatus, 30000); | window.setInterval(updateStatus, 30000); | ||
window.setInterval(updateRoundTime, 1000); | window.setInterval(updateRoundTime, 1000); | ||
})(); | |||
/* RedStar persistent top search */ | |||
(() => { | |||
function installTopSearch() { | |||
if (document.querySelector('.rs-top-search')) { | |||
return true; | |||
} | |||
const header = document.querySelector('.citizen-header'); | |||
const drawer = document.querySelector('.citizen-drawer'); | |||
if (!header || !drawer) { | |||
return false; | |||
} | |||
const form = document.createElement('form'); | |||
form.className = 'rs-top-search'; | |||
form.method = 'get'; | |||
form.action = '/index.php'; | |||
form.setAttribute('role', 'search'); | |||
const hiddenTitle = document.createElement('input'); | |||
hiddenTitle.type = 'hidden'; | |||
hiddenTitle.name = 'title'; | |||
hiddenTitle.value = 'Special:Search'; | |||
const icon = document.createElement('span'); | |||
icon.className = 'rs-top-search__icon'; | |||
icon.setAttribute('aria-hidden', 'true'); | |||
const input = document.createElement('input'); | |||
input.className = 'rs-top-search__input'; | |||
input.type = 'search'; | |||
input.name = 'search'; | |||
input.placeholder = 'Искать в Красной Звезде'; | |||
input.autocomplete = 'off'; | |||
input.spellcheck = false; | |||
input.setAttribute('aria-label', 'Поиск по Красной Звезде'); | |||
form.append(hiddenTitle, icon, input); | |||
drawer.insertAdjacentElement('afterend', form); | |||
return true; | |||
} | |||
if (!installTopSearch()) { | |||
const observer = new MutationObserver(() => { | |||
if (installTopSearch()) { | |||
observer.disconnect(); | |||
} | |||
}); | |||
observer.observe(document.documentElement, { | |||
childList: true, | |||
subtree: true | |||
}); | |||
} | |||
})(); | })(); | ||
Версия от 15:54, 29 сентября 2026
(() => {
const root = document.getElementById('rs-server-status');
if (!root) {
return;
}
const state = document.getElementById('rs-status-state');
const map = document.getElementById('rs-status-map');
const time = document.getElementById('rs-status-time');
const preset = document.getElementById('rs-status-preset');
const players = document.getElementById('rs-status-players');
const maxPlayers = document.getElementById('rs-status-max');
let roundStart = null;
let runLevel = 0;
function formatDuration(milliseconds) {
if (!Number.isFinite(milliseconds) || milliseconds < 0) {
return '—';
}
const totalMinutes = Math.floor(milliseconds / 60000);
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
if (hours > 0) {
return `${hours} ч ${minutes} мин`;
}
return `${minutes} мин`;
}
function updateRoundTime() {
if (runLevel !== 1 || roundStart === null) {
time.textContent = '—';
return;
}
time.textContent = formatDuration(Date.now() - roundStart);
}
function setOffline() {
root.classList.add('rs-home-status--offline');
state.textContent = 'Сервер недоступен';
map.textContent = '—';
time.textContent = '—';
preset.textContent = '—';
players.textContent = '0';
maxPlayers.textContent = '0';
roundStart = null;
runLevel = 0;
}
function setOnline(data) {
root.classList.remove('rs-home-status--offline');
const currentPlayers =
Number.isInteger(data.players)
? data.players
: 0;
const maximum =
Number.isInteger(data.soft_max_players)
? data.soft_max_players
: 0;
runLevel =
Number.isInteger(data.run_level)
? data.run_level
: 0;
switch (runLevel) {
case 1:
state.textContent = 'Идёт раунд';
break;
case 2:
state.textContent = 'Раунд завершён';
break;
default:
state.textContent = 'Ожидание раунда';
break;
}
if (runLevel === 0) {
map.textContent = '—';
} else {
map.textContent =
typeof data.map === 'string' && data.map.trim()
? data.map.trim()
: '—';
}
preset.textContent =
typeof data.preset === 'string' && data.preset.trim()
? data.preset.trim()
: '—';
players.textContent = String(currentPlayers);
maxPlayers.textContent = String(maximum);
if (
runLevel === 1 &&
typeof data.round_start_time === 'string' &&
data.round_start_time.length > 0
) {
const parsed = Date.parse(data.round_start_time);
roundStart = Number.isNaN(parsed) ? null : parsed;
} else {
roundStart = null;
}
updateRoundTime();
}
async function updateStatus() {
try {
const response = await fetch('/server-status', {
cache: 'no-store',
headers: {
Accept: 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
setOnline(data);
} catch (error) {
console.warn('RedStar server status unavailable:', error);
setOffline();
}
}
updateStatus();
window.setInterval(updateStatus, 30000);
window.setInterval(updateRoundTime, 1000);
})();
/* RedStar persistent top search */
(() => {
function installTopSearch() {
if (document.querySelector('.rs-top-search')) {
return true;
}
const header = document.querySelector('.citizen-header');
const drawer = document.querySelector('.citizen-drawer');
if (!header || !drawer) {
return false;
}
const form = document.createElement('form');
form.className = 'rs-top-search';
form.method = 'get';
form.action = '/index.php';
form.setAttribute('role', 'search');
const hiddenTitle = document.createElement('input');
hiddenTitle.type = 'hidden';
hiddenTitle.name = 'title';
hiddenTitle.value = 'Special:Search';
const icon = document.createElement('span');
icon.className = 'rs-top-search__icon';
icon.setAttribute('aria-hidden', 'true');
const input = document.createElement('input');
input.className = 'rs-top-search__input';
input.type = 'search';
input.name = 'search';
input.placeholder = 'Искать в Красной Звезде';
input.autocomplete = 'off';
input.spellcheck = false;
input.setAttribute('aria-label', 'Поиск по Красной Звезде');
form.append(hiddenTitle, icon, input);
drawer.insertAdjacentElement('afterend', form);
return true;
}
if (!installTopSearch()) {
const observer = new MutationObserver(() => {
if (installTopSearch()) {
observer.disconnect();
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
}
})();