MediaWiki:Common.js: различия между версиями

Материал из Space Station 14 Вики
мНет описания правки
мНет описания правки
 
(не показано 586 промежуточных версий 3 участников)
Строка 1: Строка 1:
/*WikiEditor/Викификатор*/
const IFRAME_CONFIG = {
if ( $.inArray( mw.config.get( 'wgAction' ), ['edit', 'submit'] ) !== -1 ) {
iframe1: {
        mw.loader.load( '//ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&action=raw&ctype=text/javascript' );
src: 'https://example.com',
srcdoc: '',
width: '600',
height: '400',
name: 'iframe1',
allow: 'clipboard-write',
referrerpolicy: 'no-referrer',
sandbox: 'allow-same-origin',
id: 'iframe1'
},
iframeMapRender: {
srcdoc: '<!DOCTYPE html><html data-bs-theme="dark" lang="ru"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1" name="viewport"><meta content="Просмотр карт SS14 Kerisar" name="description"><title>🗺 Просмотр карт SS14 Kerisar 🦎</title><link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" rel="stylesheet"><style>img{image-rendering:pixelated}body{background-color:#2c2c2c}.image-container{width:100%;height:70vh;border:1px solid rgba(255,255,255,.1);position:relative;overflow:hidden;margin-top:20px;margin-left:auto;margin-right:auto}.image-container img{max-width:none;height:auto;position:absolute;top:0;left:0}:fullscreen .image-container{border:none}#buttonsGroupPlus{display:flex;justify-content:space-between;flex-direction:row}</style></head><body><div class="container"><div class="mb-3 d-flex flex-wrap" id="folder-list"></div><div class="mb-3" id="file-list"></div><div class="image-container" id="image-container"><img alt="Изображение" id="panzoom-image" src=""></div><div class="m-1" id="buttonsGroupPlus"><button class="btn btn-outline-light btn-sm" id="fullscreen-toggle">Полный экран</button> <button class="btn btn-outline-light btn-sm" id="open-in-new-window">Открыть в отдельном окне</button><a class="btn btn-outline-light btn-sm" href="https://station14.ru" target="_top">Вернуться на главную страницу вики</a></div></div><script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"></script><script src="https://unpkg.com/@panzoom/[email protected]/dist/panzoom.min.js"></script><script>async function fetchFolderData(e){const t=await fetch(e),n=await t.text();return{folderNames:[...n.matchAll(/{"count":{.*?},"name":"(.*?)",.*?"type":"folder"}/g)].map(e=>e[1]),fileNames:[...n.matchAll(/{"name":"(.*?)",.*?"type":"file"}/g)].map(e=>e[1])}}async function processFolder(e){const t="https://api.codetabs.com/v1/proxy/?quest=https://cloud.mail.ru/public/6P5o/RLnoP6pLa/"+e,{folderNames:n,fileNames:o}=await fetchFolderData(t),l=n.filter(e=>"MapImages"!==e);return{name:e,files:o.sort(),subfolders:await Promise.all(l.map(t=>processFolder(e+"/"+t))).then(e=>e.sort((e,t)=>e.name.localeCompare(t.name,void 0,{numeric:!0})))}}function displayFolderData(e){const t=document.createElement("div");t.classList.add("folder");const n=document.createElement("button");n.classList.add("btn","btn-outline-light","m-1","btn-sm"),n.textContent=e.name,n.onclick=(()=>loadFiles(e,n)),t.appendChild(n),document.getElementById("folder-list").appendChild(t)}function loadFiles(e,t){const n=document.getElementById("file-list");n.innerHTML="",e.files.forEach(t=>{const o=document.createElement("button");o.textContent=t,o.classList.add("btn","btn-outline-light","m-1","btn-sm"),o.onclick=(()=>showMap(e.name,t,o)),n.appendChild(o)}),document.querySelectorAll("#folder-list button").forEach(e=>e.classList.remove("active")),t.classList.add("active")}function showMap(e,t,n){const o="https://thumb.cloud.mail.ru/weblink/thumb/xw1/6P5o/RLnoP6pLa/"+e+"/"+t,l=document.getElementById("panzoom-image");l.src=o;const a=Panzoom(l,{canvas:!0}),c=l.parentElement;c.addEventListener("wheel",a.zoomWithWheel),c.addEventListener("wheel",function(e){e.shiftKey&&a.zoomWithWheel(e)});const s=document.getElementById("open-in-new-window");s.style.display="block",s.onclick=(()=>window.open(o,"_blank")),document.querySelectorAll("#file-list button").forEach(e=>e.classList.remove("active")),n.classList.add("active")}function toggleFullscreen(){const e=document.getElementById("image-container");document.fullscreenElement?document.exitFullscreen():e.requestFullscreen().catch(e=>console.log("Ошибка при попытке открыть в полноэкранном режиме"))}document.getElementById("fullscreen-toggle").addEventListener("click",toggleFullscreen),async function(){const{folderNames:e,fileNames:t}=await fetchFolderData("https://api.codetabs.com/v1/proxy/?quest=https://cloud.mail.ru/public/6P5o/RLnoP6pLa");(await Promise.all(e.filter(e=>"MapImages"!==e).map(e=>processFolder(e)))).forEach(e=>{displayFolderData(e)})}().catch(e=>{console.error("Ошибка при запросе:",e)});</script></body></html>',
width: '100%',
height: '100%',
name: 'iframeMapRender',
id: 'iframeMapRender'
},
iframeSkillsTableRed: {
src: 'https://docs.google.com/spreadsheets/d/1AvfEvRdw98iezJk2i0DVJpTgoJu2sgLnhMK9fp-LqFk/edit?gid=189048440#gid=189048440',
width: '100%',
height: '1900px',
id: "iframeSkillsTableRed"
},
};
const currentURL = window.location.href;
const serversStatus = [{
name: "server-main",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/main/server/status",
serverconnect: "game2.station14.ru/main/server"
}, {
name: "server-nova",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/nova/server/status",
serverconnect: "game2.station14.ru/nova/server"
}, {
name: "server-athara",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/athara/server/status",
serverconnect: "game2.station14.ru/athara/server"
}, {
name: "server-solaris",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/solaris/server/status",
serverconnect: "game2.station14.ru/solaris/server"
}, {
name: "server-echo",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/echo/server/status",
serverconnect: "game2.station14.ru/echo/server"
}, {
name: "server-elysium",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/elysium/server/status",
serverconnect: "game2.station14.ru/elysium/server"
}, {
name: "server-nebula",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/nebula/server/status",
serverconnect: "game2.station14.ru/nebula/server"
}, {
name: "server-wl",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/wl/server/status",
serverconnect: "game2.station14.ru/wl/server"
}, {
name: "server-frontier",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://arles.station14.ru/frontier-main/server/status",
serverconnect: "arles.station14.ru/frontier-main/server"
}, {
name: "server-fallout",
connect: "https://api.codetabs.com/v1/proxy/?quest=http://188.92.78.98:1221/status",
serverconnect: "188.92.78.98:1221"
}, {
name: "server-marines",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game1.station14.ru/marines-main/server/status",
serverconnect: "game1.station14.ru/marines-main/server"
}, {
name: "server-stalker",
connect: "https://api.codetabs.com/v1/proxy/?quest=http://game.stalkers14.xyz/status",
serverconnect: "game.stalkers14.xyz"
}];
 
function getXHRInfo(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject('Ошибка при выполнении запроса: ' + xhr.status);
}
};
xhr.onerror = function() {
reject('Ошибка при выполнении запроса');
};
xhr.send();
});
}
 
function updateServerInfoByConnect(connect, name) {
getServerTime().then(function(currentUnixTime) {
return getXHRInfo(connect).then(function(serverData) {
var unixStartRound = getUnixTime(serverData.round_start_time);
var timeDisplay = unixStartRound ? secondsToDHM(currentUnixTime - unixStartRound) : "–";
var currentPlayers = serverData.players;
var maxPlayers = serverData.soft_max_players;
// Вычисляем процент
var percentage = maxPlayers > 0 ? Math.round((currentPlayers / maxPlayers) * 100) : 0;
// Форматируем строку с количеством игроков
var playersDisplay = currentPlayers && maxPlayers ? currentPlayers + '/' + maxPlayers : "–";
// Функция для проверки на пустые данные
function checkValue(value) {
return value ? value : "–";
}
var serverInfo = {
name: checkValue(serverData.name),
round: checkValue(serverData.round_id),
status: checkValue(serverData.run_level),
map: checkValue(serverData.map),
time: timeDisplay,
players: playersDisplay,
preset: checkValue(serverData.preset),
percentage: percentage
};
updateServerInfo(serverInfo, name);
//console.log("serverInfo", serverInfo, "currentUnixTime", currentUnixTime,"unixStartRound", unixStartRound);
});
}).catch(function(error) {
console.error(error);
});
}
 
function getUnixTime(dateString) {
return Math.floor(new Date(dateString).getTime() / 1000); // Делим на 1000, чтобы получить секунды
}
 
function secondsToDHM(seconds) {
var days = Math.floor(seconds / 86400);
var hours = Math.floor((seconds % 86400) / 3600);
var minutes = Math.floor((seconds % 3600) / 60);
var result = "";
if (days > 0) result += days + " дн, ";
if (hours > 0) result += hours + " ч ";
// Проверка на наличие минут
if (minutes > 0) {
result += minutes + " мин";
} else {
result += "–"; // Символ ожидания, если минут нет
}
return result.trim();
}
 
function getServerTime() {
return fetch('https://station14.ru/api.php?action=query&meta=siteinfo&siprop=general&format=json').then(
function(response) {
return response.json();
}).then(function(data) {
return getUnixTime(data.query.general.time);
});
}
 
function updateServerInfo(serverObj, serverName) {
var serverStatusFrame = document.getElementById(serverName);
var statusText = {
0: "Лобби",
1: "Раунд идёт",
2: "Завершение"
};
serverStatusFrame.querySelector(".serverInfoRoundSet").textContent = "#" + serverObj.round;
serverStatusFrame.querySelector(".serverStatusSet").textContent = statusText[serverObj.status] ||
"Неизвестный статус";
serverStatusFrame.querySelector(".serverMapSet").textContent = serverObj.map;
serverStatusFrame.querySelector(".serverTimeSet").textContent = serverObj.time;
serverStatusFrame.querySelector(".serverPlayersSet").textContent = serverObj.players;
serverStatusFrame.querySelector(".serverPresetSet").textContent = serverObj.preset;
// Получаем строку подключения из serversStatus
const serverData = serversStatus.find(function(server) {
return server.name === serverName;
});
var connectionStringElement = serverStatusFrame.querySelector(".serverConnectSet");
if (connectionStringElement) {
connectionStringElement.textContent = serverData ? serverData.serverconnect : '-'; // Устанавливаем строку подключения
}
// Обновляем прогресс-бар
var progressBar = serverStatusFrame.querySelector(".progressBar"); // Предполагаем, что у вас есть элемент для прогресс-бара
if (progressBar) {
progressBar.style.width = serverObj.percentage + '%'; // Устанавливаем ширину прогресс-бара
}
// Обновляем отображение процента
var percentageDisplay = serverStatusFrame.querySelector(".percentageDisplay"); // Элемент для отображения процента
if (percentageDisplay) {
percentageDisplay.textContent = serverObj.percentage + '%'; // Устанавливаем текст с процентом
}
}
 
function updateAllServersInfo() {
serversStatus.forEach(function(server) {
updateServerInfoByConnect(server.connect, server.name);
});
}
 
function copyToClipboard(connectUrl) {
const copyIcons = document.querySelectorAll('.copy-icon');
copyIcons.forEach(function(icon) {
icon.addEventListener('click', function() {
// Находим предыдущий элемент
const previousElement = this.previousElementSibling;
if (previousElement) {
// Получаем текстовое содержимое
const textToCopy = previousElement.textContent;
const tempInput = document.createElement('input');
tempInput.value = textToCopy;
document.body.appendChild(tempInput);
tempInput.select();
document.execCommand('copy');
document.body.removeChild(tempInput);
// Визуальный эффект
this.style.opacity = '0.5'; // Сменяем прозрачность
setTimeout(function() {
this.style.opacity = '1'; // Возвращаем прозрачность
}.bind(this), 200); // Через 1 секунду
}
});
});
}
 
function escapeAndMinifyCSS(css) {
return css.replace(/\\/g, '\\\\') // Экранируем обратный слэш
.replace(/\n/g, '') // Удаляем переносы строк (по желанию)
.replace(/\/\*[\s\S]*?\*\//g, '') // Удаляем комментарии
.replace(/\s+/g, ' ') // Заменяем множественные пробелы на один
.trim(); // Удаляем пробелы в начале и конце
}
const addedStyles = new Set();
 
function customCSS(textCSS) {
const escapedCSS = escapeAndMinifyCSS(textCSS); // Экранируем CSS
// Проверяем, был ли уже добавлен этот CSS
if (!addedStyles.has(escapedCSS)) {
addedStyles.add(escapedCSS); // Добавляем в множество уникальных стилей
const styleSheet = document.createElement("style");
styleSheet.textContent = escapedCSS;
document.head.appendChild(styleSheet);
}
}
 
function createIframe(id) {
const config = IFRAME_CONFIG[id];
if (!config) return;
const iframe = document.createElement('iframe');
if (config.src && config.src !== "") {
iframe.src = config.src;
}
if (config.srcdoc && config.srcdoc !== "") {
iframe.srcdoc = config.srcdoc;
}
if (config.width && config.width !== "") {
iframe.width = config.width;
} else {
iframe.width = '100%'; // Значение по умолчанию
}
if (config.height && config.height !== "") {
iframe.height = config.height;
} else {
iframe.height = '400px'; // Значение по умолчанию
}
if (config.name && config.name !== "") {
iframe.name = config.name;
}
if (config.allow && config.allow !== "") {
iframe.allow = config.allow;
}
if (config.referrerpolicy && config.referrerpolicy !== "") {
iframe.referrerPolicy = config.referrerpolicy;
}
if (config.sandbox && config.sandbox !== "") {
iframe.sandbox = config.sandbox;
}
iframe.id = config.id || ''; // id может быть пустым, если не задано
return iframe;
}
// Функция для увеличения яркости цвета
function brightenColor(color, factor) {
function getBrightness(r, g, b) {
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
 
function isGray(r, g, b) {
var maxDiff = 20; // Максимальное допустимое отклонение между RGB для серого
return Math.abs(r - g) < maxDiff && Math.abs(g - b) < maxDiff && Math.abs(r - b) < maxDiff;
}
 
var rgbValues = color.match(/\d+(\.\d+)?/g);
var r = parseInt(rgbValues[0], 10);
var g = parseInt(rgbValues[1], 10);
var b = parseInt(rgbValues[2], 10);
var a = rgbValues.length === 4 ? parseFloat(rgbValues[3]) : 1;
 
var brightness = getBrightness(r, g, b);
 
if (factor === undefined) {
if (brightness <= 40) {
factor = 6;
} else if (brightness <= 180) {
factor = 4;
} else {
factor = 0;
}
}
 
// Если цвет серый, уменьшаем фактор
if (isGray(r, g, b)) {
factor = Math.max(1, factor * 0.50);
}
 
// Добавляем фактор вместо умножения
r = Math.min(255, r + factor);
g = Math.min(255, g + factor);
b = Math.min(255, b + factor);
 
return a < 1 ? 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')' : 'rgb(' + r + ', ' + g + ', ' + b + ')';
}
}


var customizeToolbar = function() {
// Функция для подсветки ячеек в таблице при наведении
function applyHighlighting() {
if (/Mobi|Android/i.test(navigator.userAgent)) {
return;
}
var tables = document.querySelectorAll('.wikitable:not(.no-highlight-table)');
Array.prototype.forEach.call(tables, function(table) {
var tbody = table.querySelector('tbody');
var thead = table.querySelector('thead');
var noHeader = table.classList.contains('no-header-table');
if (tbody) {
// Получаем все строки <tr> внутри первого уровня <tbody>
var rows = Array.prototype.slice.call(tbody.querySelectorAll('tr')).filter(function(row) {
// Проверяем, что <tr> находится на первом уровне, и исключаем строки с вложенными таблицами
return row.parentElement === tbody && !row.querySelector('table');
});
 
// Пропускаем первую строку, если нет <thead> и нет класса 'no-header-table'
var topLevelRows = (!thead && !noHeader) ? rows.slice(1) : rows;
var hasInvalidRowspan = false;
var hasTooManyRowspan = false;
 
// Проверка на ошибки в rowspan
Array.prototype.forEach.call(topLevelRows, function(row) {
var cells = Array.prototype.slice.call(row.querySelectorAll('td, th')).filter(function(cell) {
return !cell.classList.contains('mobile');
});
var cellCount = cells.length;
var rowspanCount = cells.filter(function(cell) {
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1'; // Игнорируем rowspan="1"
}).length;
 
// Проверка на слишком большое количество rowspan или неправильное расположение rowspan
if (rowspanCount > 2) {
hasTooManyRowspan = true;
return;
}
 
// Проверяем, что ячейки с rowspan находятся по краям строки
var hasValidRowspanEdge = cells.some(function(cell, index) {
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1' && (index === 0 || index === cells.length - 1);
});
 
// Если ячейки с rowspan находятся не по краям
if (!hasValidRowspanEdge && cells.some(function(cell, index) {
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1' && index > 0 && index < cells.length - 1;
})) {
hasInvalidRowspan = true;
}
});
 
// Если есть ошибки в rowspan, выходим
if (hasTooManyRowspan || hasInvalidRowspan) return;
 
// Обработка наведения на строки и ячейки
Array.prototype.forEach.call(topLevelRows, function(row, rowIndex) {
var cells = Array.prototype.slice.call(row.querySelectorAll('td, th'));
// Сохраняем оригинальные стили для каждой ячейки
var originalStyles = cells.map(function(cell) {
return {
backgroundColor: getComputedStyle(cell).backgroundColor,
color: getComputedStyle(cell).color
};
});
 
// Наведение на строку (tr)
row.addEventListener('mouseover', function() {
highlightRow(row, rowIndex, true);
});
row.addEventListener('mouseout', function() {
highlightRow(row, rowIndex, false);
});
 
// Наведение на ячейки с rowspan
Array.prototype.forEach.call(cells, function(cell, cellIndex) {
// Обрабатываем только ячейки с rowspan > 1
if (cell.hasAttribute('rowspan') && parseInt(cell.getAttribute('rowspan')) > 1) {
var rowspan = parseInt(cell.getAttribute('rowspan'));
 
// Обработка rowspan ячейки
cell.addEventListener('mouseover', function() {
// Отключаем обработку строки при наведении на rowspan ячейку
row.classList.add('highlighted');
highlightRowspanArea(rowIndex, cellIndex, rowspan, true);
});
 
cell.addEventListener('mouseout', function() {
// Восстанавливаем состояние строки при уходе курсора
row.classList.remove('highlighted');
highlightRowspanArea(rowIndex, cellIndex, rowspan, false);
});
}
});
 
// Функция подсветки строки (только текущее tr)
function highlightRow(row, rowIndex, highlight) {
if (row.classList.contains('highlighted')) return; // Избегаем повторного применения подсветки
var rowCells = Array.prototype.slice.call(row.querySelectorAll('td, th'));
Array.prototype.forEach.call(rowCells, function(cell, cellIndex) {
// Подсвечиваем только ячейки, не имеющие атрибут rowSpan или с rowspan="1"
if (!cell.hasAttribute('rowspan') || parseInt(cell.getAttribute('rowspan')) === 1) {
var cellStyle = getComputedStyle(cell);
cell.style.setProperty('background-color', highlight ? brightenColor(cellStyle.backgroundColor) :
originalStyles[cellIndex].backgroundColor, 'important');
cell.style.setProperty('color', highlight ? brightenColor(cellStyle.color) : originalStyles[cellIndex].color, 'important');
}
});
}


$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
// Функция подсветки для ячеек с rowspan (подсвечивает все строки, которые охватывает ячейка)
        'section': 'advanced',
function highlightRowspanArea(rowIndex, cellIndex, rowspan, highlight) {
        'group': 'format',
for (var i = 0; i < rowspan; i++) {
        'tools': {
var targetRow = topLevelRows[rowIndex + i];
                'wikify': {
if (targetRow) {
                        label: 'Викификатор',
var targetCells = Array.prototype.slice.call(targetRow.querySelectorAll('td, th'));
                        type: 'button',
// Обработка ячейки в каждой строке, затронутой rowspan
                        icon: '//upload.wikimedia.org/wikipedia/commons/0/06/Wikify-toolbutton.png',
Array.prototype.forEach.call(targetCells, function(targetCell) {
                            action: {
var targetCellStyle = getComputedStyle(targetCell);
                                  type: 'callback',
// Сохраняем оригинальные стили для каждой ячейки, если подсветка включена
                                      execute: function(context){
if (highlight) {
                                              Wikify();
targetCell.originalBackground = targetCellStyle.backgroundColor;
                                      }
targetCell.originalColor = targetCellStyle.color;
                            }
}
                }
// Применяем подсветку или восстанавливаем оригинальные стили
        }
targetCell.style.setProperty('background-color', highlight ? brightenColor(targetCellStyle.backgroundColor) :
} );
targetCell.originalBackground, 'important');
};
targetCell.style.setProperty('color', highlight ? brightenColor(targetCellStyle.color) :
targetCell.originalColor, 'important');
if ( $.inArray( mw.config.get( 'wgAction' ), ['edit', 'submit'] ) !== -1 ) {
});
        mw.loader.using( 'user.options', function () {
}
                if ( mw.user.options.get('usebetatoolbar') ) {
}
                        mw.loader.using( 'ext.wikiEditor.toolbar', function () {
}
                                $(document).ready( customizeToolbar );
});
                        } );
}
                }
});
        } );
}
}
// Функция для логики меню, создаваемого модулем CategoryMenu
function initCategorySwitcher() {
var categories = document.querySelectorAll('.navigation__categories > div');
var menus = document.querySelectorAll('.navigation__menu-item');
var contentDivs = document.querySelectorAll('.navigation__content > div');
var menuItems = document.querySelectorAll('.navigation__menu-item > div');
var currentCategoryIndex = 0; // Индекс текущей активной категории


const currentUrl = window.location.href;
// Генерация ID из текста
if (currentUrl.contain("Kerisar")) {
function generateIdFromText(text) {
console.log("Скрипт успешно работает");
return text.trim().replace(/\s+/g, '-').replace(/[^a-zа-яёA-ZА-ЯЁ0-9\-]/g, '');
console.log(currentUrl);
}
 
// Присвоение ID категориям и пунктам меню
function assignIds() {
for (var i = 0; i < categories.length; i++) {
var category = categories[i];
category.setAttribute('id', generateIdFromText(category.textContent || category.innerText));
 
var menu = menus[i];
var menuItems = menu.querySelectorAll('div');
for (var j = 0; j < menuItems.length; j++) {
menuItems[j].setAttribute('id', generateIdFromText(menuItems[j].textContent || menuItems[j].innerText));
}
}
}
 
assignIds(); // Вызов функции для присвоения ID
 
// Удаление класса active у всех переданных элементов
function clearActiveElements(elements) {
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove('active');
}
}
 
// Переключение категорий
function switchCategory(index) {
clearActiveElements(menus);
clearActiveElements(contentDivs);
clearActiveElements(categories);
 
var selectedCategory = categories[index];
if (selectedCategory) {
selectedCategory.classList.add('active');
var selectedMenu = document.querySelector('.' + selectedCategory.classList[0] + '-menu');
if (selectedMenu) {
selectedMenu.classList.add('active');
switchContent(selectedMenu.querySelector('div')); // Открытие первого пункта меню
}
}
 
currentCategoryIndex = index;
updateArrowStates(); // Обновление состояния стрелок
}
 
// Переключение контента в меню
function switchContent(menuItem) {
clearActiveElements(menuItems);
clearActiveElements(contentDivs);
 
if (menuItem) {
var contentClass = menuItem.className + '-content';
var content = document.querySelector('.' + contentClass);
if (content) {
content.classList.add('active');
menuItem.classList.add('active');
}
}
}
 
// Обновление состояния стрелок (активные/неактивные)
function updateArrowStates() {
var prevArrow = document.getElementById('prev-category');
var nextArrow = document.getElementById('next-category');
 
prevArrow.classList.toggle('disabled', currentCategoryIndex === 0);
prevArrow.style.pointerEvents = currentCategoryIndex === 0 ? 'none' : 'auto';
 
nextArrow.classList.toggle('disabled', currentCategoryIndex === categories.length - 1);
nextArrow.style.pointerEvents = currentCategoryIndex === categories.length - 1 ? 'none' : 'auto';
}
 
// Стрелки для переключения категорий
document.getElementById('prev-category').addEventListener('click', function() {
if (currentCategoryIndex > 0) {
switchCategory(--currentCategoryIndex); // Переключение на новую категорию
}
});
 
document.getElementById('next-category').addEventListener('click', function() {
if (currentCategoryIndex < categories.length - 1) {
switchCategory(++currentCategoryIndex); // Переключение на новую категорию
}
});
 
// Функция для обработки якорей
function handleAnchorChange() {
var anchor = window.location.hash.substring(1); // Получаем текущий хеш без символа #
var decodedAnchor = decodeURIComponent(anchor); // Декодируем хеш
var found = false;
 
// Проверка пунктов меню
for (var i = 0; i < menuItems.length; i++) {
if (menuItems[i].id === decodedAnchor) { // Сравниваем с декодированным значением
var categoryIndex = Array.prototype.indexOf.call(categories, menuItems[i].closest('.navigation__menu-item').previousElementSibling);
if (categoryIndex !== -1) {
switchCategory(categoryIndex); // Открываем категорию
switchContent(menuItems[i]);  // Открываем пункт меню
found = true; // Якорь найден
}
break; // Выход из цикла, если якорь найден
}
}
 
// Проверка категорий, если якорь не найден в пунктах меню
if (!found) {
for (var i = 0; i < categories.length; i++) {
if (categories[i].id === decodedAnchor) { // Сравниваем с декодированным значением
switchCategory(i); // Открываем категорию
found = true; // Якорь найден
break;
}
}
}
}
 
// Проверяем якорь при изменении URL
window.addEventListener('hashchange', handleAnchorChange);
 
// Инициализация: открытие первой категории и первого пункта
if (categories.length > 0) {
assignIds(); // Присвоить ID в начале
handleAnchorChange(); // Обработка начального якоря
 
// Проверка наличия якоря и открытие первой категории только если ID не найден
if (!window.location.hash) {
switchCategory(0);
} else {
switchCategory(currentCategoryIndex);
}
 
updateArrowStates();
}
 
// Клик по элементам меню
for (var i = 0; i < menuItems.length; i++) {
(function(menuItem) {
menuItem.addEventListener('click', function() {
switchContent(menuItem); // Переключение контента при клике на пункт меню
// Убрали изменение хеша при клике
});
})(menuItems[i]);
}
 
document.querySelector('.navigation__menu-toggle').addEventListener('click', function() {
var menu = document.querySelector('.navigation__menu-container');
menu.classList.toggle('active'); // Переключение класса для показа/скрытия меню
this.classList.toggle('active'); // Переключение для перемещения кнопки
});
}
}
const currentPageTitle = document.title;
$(document).ready(function() {
var serversStatus = document.querySelectorAll('.serversStatus');
if (serversStatus.length > 0) {
updateAllServersInfo();
// Перезапускать каждую минуту (60000 мс)
setInterval(updateAllServersInfo, 60000);
}
var cssEls = document.querySelectorAll('.customCSS');
if (cssEls.length > 0) {
for (var j = 0; j < cssEls.length; j++) {
const textCSS = cssEls[j].textContent;
customCSS(textCSS);
}
}
const copyServerConnectionIcon = document.querySelectorAll('.copyServerConnectionIcon');
copyServerConnectionIcon.forEach(function(icon) {
icon.addEventListener('click', function() {
const connectUrl = this.getAttribute('data-connect');
copyToClipboard(connectUrl);
});
});
copyToClipboard();
var divs = document.querySelectorAll('.customIFrame');
if (divs) {
for (var i = 0; i < divs.length; i++) {
var div = divs[i];
var id = div.id;
var iframe = createIframe(id);
if (iframe) {
div.appendChild(iframe);
}
}
}
var tables = document.querySelectorAll('.wikitable');
if (tables.length > 0) {
setTimeout(function() {
applyHighlighting();
}, 500);
}
if (currentPageTitle.includes("Kerisar")) {
console.log("Привет, Kerisar!");
var button = document.createElement("button");
button.innerText = "Создать архив";
document.getElementById("archivetest").appendChild(button);
button.onclick = function() {
var apiUrl =
"https://station14.ru/api.php?action=parse&page=Шаблон:Бумажная работа/paperWork.json&prop=text&formatversion=2&format=json";
fetch(apiUrl).then(function(response) {
return response.json();
}).then(function(data) {
var text = data.parse.text;
//console.log(text);
// Извлекаем содержимое между [testarchivestart] и [testarchivestop]
var startTag = "[testarchivestart]";
var endTag = "[testarchivestop]";
var startIndex = text.indexOf(startTag);
var endIndex = text.indexOf(endTag);
if (startIndex !== -1 && endIndex !== -1) {
var extractedContent = text.substring(startIndex + startTag.length, endIndex);
// Декодируем base64 в бинарные данные
var binaryString = window.atob(extractedContent);
var len = binaryString.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
// Создаем Blob из бинарных данных
var blob = new Blob([bytes], {
type: "application/zip"
});
// Создаем ссылку для скачивания
var link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "archive.zip"; // Имя файла для скачивания
link.innerText = "Скачать архив";
document.getElementById("archivetest").appendChild(link);
} else {
alert("Теги [testarchivestart] и [testarchivestop] не найдены.");
}
}).catch(function(error) {
console.error("Ошибка:", error);
});
};
}
var categoriesExist = document.querySelectorAll('.navigation');
if (categoriesExist.length > 0) {
initCategorySwitcher();
}
});
/*WikiEditor/Викификатор*/
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1) {
mw.loader.load(
'//ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&action=raw&ctype=text/javascript');
}
var customizeToolbar = function() {
$('#wpTextbox1').wikiEditor('addToToolbar', {
'section': 'advanced',
'group': 'format',
'tools': {
'wikify': {
label: 'Викификатор',
type: 'button',
icon: '//upload.wikimedia.org/wikipedia/commons/0/06/Wikify-toolbutton.png',
action: {
type: 'callback',
execute: function(context) {
Wikify();
}
}
}
}
});
};
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1) {
mw.loader.using('user.options', function() {
if (mw.user.options.get('usebetatoolbar')) {
mw.loader.using('ext.wikiEditor.toolbar', function() {
$(document).ready(customizeToolbar);
});
}
});
}
/**
* Taken from https://wiki.ss220.space/index.php?title=MediaWiki:Common.js&oldid=35626
*/
/* Variables for interface text used throughout the script, for ease of translating */
var i18n = {
// Collapsible elements and page loader
hideText: 'скрыть',
showText: 'показать',
// Page loader
loadErrorTitle: 'Возникла ошибка при загрузке содержимого'
};
var mcw = window.mcw = {};
/* Keep track of delegated events on dynamic content */
mcw.events = {};
/* Fired whenever wiki content is added. (#mw-content-text, live preview, load page, etc.) */
mw.hook('wikipage.content').add(function($wikipageContent) {
/**
* Page loader
*
* Allows a page to be downloaded and displayed on demand.
* Use with Template:LoadPage and Template:LoadBox
*/
(function() {
var $loadPage = $wikipageContent.find('.load-page');
if (!$loadPage.length) {
return;
}
// We need the spinner to show loading is happening, but we don't want
// to have a delay while the module downloads, so we'll load this now,
// regardless of if something is clicked
mw.loader.load('jquery.spinner');
// Create button starting with hide text
// Will be changed to the show text while calculating the maximum button size
var $buttonTemplate = $('<span>').addClass('mw-editsection-like load-page-button').append('[ ', $(
'<span>').addClass('jslink').text(i18n.hideText), ' ]');
var extractList = function($contentContainer, listClass) {
var $content = $contentContainer.find('.mw-parser-output > ul > li > ul').children(
':not(.nbttree-inherited)');
if (listClass) {
$content.addClass(listClass);
}
return $content;
};
$loadPage.each(function() {
var $body = $(this);
var page = $body.data('page');
if (!page) {
return;
}
var template = $body.data('template');
var treeview = $body.data('treeview');
var treeviewClass = $body.data('treeviewclass');
var $heading;
var $contentContainer;
var $content;
var $button = $buttonTemplate.clone();
var $buttonLink = $button.find('.jslink');
if (treeview) {
$heading = $body;
$contentContainer = $('<div>');
} else {
$heading = $body.children().first();
$contentContainer = $body.find('.load-page-content');
}
// Add the button
$heading.append($button);
// Move the edit button to the right spot
$contentContainer.find('.mw-editsection, .mw-editsection-like').insertAfter($button);
// Find max button width, and set its min-width to it
var hideWidth = $button.width();
$buttonLink.text(i18n.showText);
var showWidth = $button.width();
if (hideWidth !== showWidth) {
$button.css('min-width', hideWidth > showWidth ? hideWidth : showWidth);
}
$buttonLink.click(function() {
if ($body.hasClass('pageloader-contentloaded')) {
if ($buttonLink.text() === i18n.showText) {
if (treeview) {
$content.insertAfter($body);
} else {
$contentContainer.show();
}
$buttonLink.text(i18n.hideText);
} else {
if (treeview) {
$content.detach();
} else {
$contentContainer.hide();
}
$buttonLink.text(i18n.showText);
}
return;
}
// See if this was loaded elsewhere before making a request
var gotContent;
$('.pageloader-contentloaded').each(function() {
var $fLoader = $(this);
if ($fLoader.data('page') === page && $fLoader.data('pageloader-content')) {
$contentContainer.html($fLoader.data('pageloader-content')).removeClass('noscript');
mw.hook('wikipage.content').fire($contentContainer);
if (treeview) {
$body.find('.noscript').remove();
$content = extractList($contentContainer, treeviewClass);
$content.insertAfter($body);
}
$buttonLink.text(i18n.hideText);
$body.addClass('pageloader-contentloaded');
gotContent = true;
return false;
}
});
if (gotContent) {
return;
}
// Just in-case the spinner module is still not ready yet
var $spinner = $();
mw.loader.using('jquery.spinner', function() {
// $spinner will be false if the content somehow loaded before the module did
if ($spinner) {
$spinner = $.createSpinner().addClass('mw-editsection-like').css('min-width', $button.css(
'min-width'));
$button.hide().after($spinner);
}
});
var requestData = {
action: 'parse',
prop: 'text'
};
if (template) {
requestData.page = page;
} else {
requestData.title = mw.config.get('wgPageName');
requestData.text = '{' + '{:' + page + '}}';
}
new mw.Api().get(requestData).done(function(data) {
var html = data.parse.text['*'];
$contentContainer.html(html).removeClass('noscript');
// Resolve self-links
if (template) {
var curPage = '/' + mw.config.get('wgPageName');
$contentContainer.find('a').each(function() {
var $link = $(this);
if ($link.attr('href') === curPage) {
$link.replaceWith($('<strong>').addClass('selflink').append($link.contents()));
}
});
html = $contentContainer.html();
}
$body.data('pageloader-content', html);
// Fire content hook on the new content, running all this stuff again and more :)
mw.hook('wikipage.content').fire($contentContainer);
if (treeview) {
$body.find('.noscript').remove();
$content = extractList($contentContainer, treeviewClass);
$content.insertAfter($body);
}
$spinner.remove();
$spinner = false;
$buttonLink.text(i18n.hideText);
$button.show();
$body.addClass('pageloader-contentloaded');
}).fail(function(_, error) {
$spinner.remove();
$spinner = false;
$button.show();
var errorText = '';
if (error.textStatus) {
errorText = error.textStatus;
} else if (error.error) {
errorText = error.error.info;
}
mw.notify(errorText, {
title: i18n.loadErrorTitle,
autoHide: false
});
});
});
});
}());
/**
* Element animator
*
* Will cycle the active class on any child elements
* within an element with the animated class.
*/
(function() {
if (!mcw.animate) {
mcw.animate = setInterval(function() {
$('.animated').each(function() {
var $elem = $(this);
var $current = $elem.children('.active');
var $next = $current.nextAll(':not(.skip):first');
// Loop back to the start
if (!$next.length) {
$next = $elem.children(':not(.skip):first');
}
$current.removeClass('active');
$next.addClass('active');
});
}, 2000);
}
}());
});
// SS220 import end

Текущая версия от 12:37, 5 октября 2024

const IFRAME_CONFIG = {
	iframe1: {
		src: 'https://example.com',
		srcdoc: '',
		width: '600',
		height: '400',
		name: 'iframe1',
		allow: 'clipboard-write',
		referrerpolicy: 'no-referrer',
		sandbox: 'allow-same-origin',
		id: 'iframe1'
	},
	iframeMapRender: {
		srcdoc: '<!DOCTYPE html><html data-bs-theme="dark" lang="ru"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1" name="viewport"><meta content="Просмотр карт SS14 Kerisar" name="description"><title>🗺 Просмотр карт SS14 Kerisar 🦎</title><link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" rel="stylesheet"><style>img{image-rendering:pixelated}body{background-color:#2c2c2c}.image-container{width:100%;height:70vh;border:1px solid rgba(255,255,255,.1);position:relative;overflow:hidden;margin-top:20px;margin-left:auto;margin-right:auto}.image-container img{max-width:none;height:auto;position:absolute;top:0;left:0}:fullscreen .image-container{border:none}#buttonsGroupPlus{display:flex;justify-content:space-between;flex-direction:row}</style></head><body><div class="container"><div class="mb-3 d-flex flex-wrap" id="folder-list"></div><div class="mb-3" id="file-list"></div><div class="image-container" id="image-container"><img alt="Изображение" id="panzoom-image" src=""></div><div class="m-1" id="buttonsGroupPlus"><button class="btn btn-outline-light btn-sm" id="fullscreen-toggle">Полный экран</button> <button class="btn btn-outline-light btn-sm" id="open-in-new-window">Открыть в отдельном окне</button><a class="btn btn-outline-light btn-sm" href="https://station14.ru" target="_top">Вернуться на главную страницу вики</a></div></div><script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"></script><script src="https://unpkg.com/@panzoom/[email protected]/dist/panzoom.min.js"></script><script>async function fetchFolderData(e){const t=await fetch(e),n=await t.text();return{folderNames:[...n.matchAll(/{"count":{.*?},"name":"(.*?)",.*?"type":"folder"}/g)].map(e=>e[1]),fileNames:[...n.matchAll(/{"name":"(.*?)",.*?"type":"file"}/g)].map(e=>e[1])}}async function processFolder(e){const t="https://api.codetabs.com/v1/proxy/?quest=https://cloud.mail.ru/public/6P5o/RLnoP6pLa/"+e,{folderNames:n,fileNames:o}=await fetchFolderData(t),l=n.filter(e=>"MapImages"!==e);return{name:e,files:o.sort(),subfolders:await Promise.all(l.map(t=>processFolder(e+"/"+t))).then(e=>e.sort((e,t)=>e.name.localeCompare(t.name,void 0,{numeric:!0})))}}function displayFolderData(e){const t=document.createElement("div");t.classList.add("folder");const n=document.createElement("button");n.classList.add("btn","btn-outline-light","m-1","btn-sm"),n.textContent=e.name,n.onclick=(()=>loadFiles(e,n)),t.appendChild(n),document.getElementById("folder-list").appendChild(t)}function loadFiles(e,t){const n=document.getElementById("file-list");n.innerHTML="",e.files.forEach(t=>{const o=document.createElement("button");o.textContent=t,o.classList.add("btn","btn-outline-light","m-1","btn-sm"),o.onclick=(()=>showMap(e.name,t,o)),n.appendChild(o)}),document.querySelectorAll("#folder-list button").forEach(e=>e.classList.remove("active")),t.classList.add("active")}function showMap(e,t,n){const o="https://thumb.cloud.mail.ru/weblink/thumb/xw1/6P5o/RLnoP6pLa/"+e+"/"+t,l=document.getElementById("panzoom-image");l.src=o;const a=Panzoom(l,{canvas:!0}),c=l.parentElement;c.addEventListener("wheel",a.zoomWithWheel),c.addEventListener("wheel",function(e){e.shiftKey&&a.zoomWithWheel(e)});const s=document.getElementById("open-in-new-window");s.style.display="block",s.onclick=(()=>window.open(o,"_blank")),document.querySelectorAll("#file-list button").forEach(e=>e.classList.remove("active")),n.classList.add("active")}function toggleFullscreen(){const e=document.getElementById("image-container");document.fullscreenElement?document.exitFullscreen():e.requestFullscreen().catch(e=>console.log("Ошибка при попытке открыть в полноэкранном режиме"))}document.getElementById("fullscreen-toggle").addEventListener("click",toggleFullscreen),async function(){const{folderNames:e,fileNames:t}=await fetchFolderData("https://api.codetabs.com/v1/proxy/?quest=https://cloud.mail.ru/public/6P5o/RLnoP6pLa");(await Promise.all(e.filter(e=>"MapImages"!==e).map(e=>processFolder(e)))).forEach(e=>{displayFolderData(e)})}().catch(e=>{console.error("Ошибка при запросе:",e)});</script></body></html>',
		width: '100%',
		height: '100%',
		name: 'iframeMapRender',
		id: 'iframeMapRender'
	},
	iframeSkillsTableRed: {
		src: 'https://docs.google.com/spreadsheets/d/1AvfEvRdw98iezJk2i0DVJpTgoJu2sgLnhMK9fp-LqFk/edit?gid=189048440#gid=189048440',
		width: '100%',
		height: '1900px',
		id: "iframeSkillsTableRed"
	},
};
const currentURL = window.location.href;
const serversStatus = [{
	name: "server-main",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/main/server/status",
	serverconnect: "game2.station14.ru/main/server"
}, {
	name: "server-nova",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/nova/server/status",
	serverconnect: "game2.station14.ru/nova/server"
}, {
	name: "server-athara",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/athara/server/status",
	serverconnect: "game2.station14.ru/athara/server"
}, {
	name: "server-solaris",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/solaris/server/status",
	serverconnect: "game2.station14.ru/solaris/server"
}, {
	name: "server-echo",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/echo/server/status",
	serverconnect: "game2.station14.ru/echo/server"
}, {
	name: "server-elysium",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/elysium/server/status",
	serverconnect: "game2.station14.ru/elysium/server"
}, {
	name: "server-nebula",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/nebula/server/status",
	serverconnect: "game2.station14.ru/nebula/server"
}, {
	name: "server-wl",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/wl/server/status",
	serverconnect: "game2.station14.ru/wl/server"
}, {
	name: "server-frontier",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://arles.station14.ru/frontier-main/server/status",
	serverconnect: "arles.station14.ru/frontier-main/server"
}, {
	name: "server-fallout",
	connect: "https://api.codetabs.com/v1/proxy/?quest=http://188.92.78.98:1221/status",
	serverconnect: "188.92.78.98:1221"
}, {
	name: "server-marines",
	connect: "https://api.codetabs.com/v1/proxy/?quest=https://game1.station14.ru/marines-main/server/status",
	serverconnect: "game1.station14.ru/marines-main/server"
}, {
	name: "server-stalker",
	connect: "https://api.codetabs.com/v1/proxy/?quest=http://game.stalkers14.xyz/status",
	serverconnect: "game.stalkers14.xyz"
}];

function getXHRInfo(url) {
	return new Promise(function(resolve, reject) {
		var xhr = new XMLHttpRequest();
		xhr.open('GET', url, true);
		xhr.onload = function() {
			if (xhr.status >= 200 && xhr.status < 300) {
				resolve(JSON.parse(xhr.responseText));
			} else {
				reject('Ошибка при выполнении запроса: ' + xhr.status);
			}
		};
		xhr.onerror = function() {
			reject('Ошибка при выполнении запроса');
		};
		xhr.send();
	});
}

function updateServerInfoByConnect(connect, name) {
	getServerTime().then(function(currentUnixTime) {
		return getXHRInfo(connect).then(function(serverData) {
			var unixStartRound = getUnixTime(serverData.round_start_time);
			var timeDisplay = unixStartRound ? secondsToDHM(currentUnixTime - unixStartRound) : "–";
			var currentPlayers = serverData.players;
			var maxPlayers = serverData.soft_max_players;
			// Вычисляем процент
			var percentage = maxPlayers > 0 ? Math.round((currentPlayers / maxPlayers) * 100) : 0;
			// Форматируем строку с количеством игроков
			var playersDisplay = currentPlayers && maxPlayers ? currentPlayers + '/' + maxPlayers : "–";
			// Функция для проверки на пустые данные
			function checkValue(value) {
				return value ? value : "–";
			}
			var serverInfo = {
				name: checkValue(serverData.name),
				round: checkValue(serverData.round_id),
				status: checkValue(serverData.run_level),
				map: checkValue(serverData.map),
				time: timeDisplay,
				players: playersDisplay,
				preset: checkValue(serverData.preset),
				percentage: percentage
			};
			updateServerInfo(serverInfo, name);
			//console.log("serverInfo", serverInfo, "currentUnixTime", currentUnixTime,"unixStartRound", unixStartRound);
		});
	}).catch(function(error) {
		console.error(error);
	});
}

function getUnixTime(dateString) {
	return Math.floor(new Date(dateString).getTime() / 1000); // Делим на 1000, чтобы получить секунды
}

function secondsToDHM(seconds) {
	var days = Math.floor(seconds / 86400);
	var hours = Math.floor((seconds % 86400) / 3600);
	var minutes = Math.floor((seconds % 3600) / 60);
	var result = "";
	if (days > 0) result += days + " дн, ";
	if (hours > 0) result += hours + " ч ";
	// Проверка на наличие минут
	if (minutes > 0) {
		result += minutes + " мин";
	} else {
		result += "–"; // Символ ожидания, если минут нет
	}
	return result.trim();
}

function getServerTime() {
	return fetch('https://station14.ru/api.php?action=query&meta=siteinfo&siprop=general&format=json').then(
		function(response) {
			return response.json();
		}).then(function(data) {
		return getUnixTime(data.query.general.time);
	});
}

function updateServerInfo(serverObj, serverName) {
	var serverStatusFrame = document.getElementById(serverName);
	var statusText = {
		0: "Лобби",
		1: "Раунд идёт",
		2: "Завершение"
	};
	serverStatusFrame.querySelector(".serverInfoRoundSet").textContent = "#" + serverObj.round;
	serverStatusFrame.querySelector(".serverStatusSet").textContent = statusText[serverObj.status] ||
		"Неизвестный статус";
	serverStatusFrame.querySelector(".serverMapSet").textContent = serverObj.map;
	serverStatusFrame.querySelector(".serverTimeSet").textContent = serverObj.time;
	serverStatusFrame.querySelector(".serverPlayersSet").textContent = serverObj.players;
	serverStatusFrame.querySelector(".serverPresetSet").textContent = serverObj.preset;
	// Получаем строку подключения из serversStatus
	const serverData = serversStatus.find(function(server) {
		return server.name === serverName;
	});
	var connectionStringElement = serverStatusFrame.querySelector(".serverConnectSet");
	if (connectionStringElement) {
		connectionStringElement.textContent = serverData ? serverData.serverconnect : '-'; // Устанавливаем строку подключения
	}
	// Обновляем прогресс-бар
	var progressBar = serverStatusFrame.querySelector(".progressBar"); // Предполагаем, что у вас есть элемент для прогресс-бара
	if (progressBar) {
		progressBar.style.width = serverObj.percentage + '%'; // Устанавливаем ширину прогресс-бара
	}
	// Обновляем отображение процента
	var percentageDisplay = serverStatusFrame.querySelector(".percentageDisplay"); // Элемент для отображения процента
	if (percentageDisplay) {
		percentageDisplay.textContent = serverObj.percentage + '%'; // Устанавливаем текст с процентом
	}
}

function updateAllServersInfo() {
	serversStatus.forEach(function(server) {
		updateServerInfoByConnect(server.connect, server.name);
	});
}

function copyToClipboard(connectUrl) {
	const copyIcons = document.querySelectorAll('.copy-icon');
	copyIcons.forEach(function(icon) {
		icon.addEventListener('click', function() {
			// Находим предыдущий элемент
			const previousElement = this.previousElementSibling;
			if (previousElement) {
				// Получаем текстовое содержимое
				const textToCopy = previousElement.textContent;
				const tempInput = document.createElement('input');
				tempInput.value = textToCopy;
				document.body.appendChild(tempInput);
				tempInput.select();
				document.execCommand('copy');
				document.body.removeChild(tempInput);
				// Визуальный эффект
				this.style.opacity = '0.5'; // Сменяем прозрачность
				setTimeout(function() {
					this.style.opacity = '1'; // Возвращаем прозрачность
				}.bind(this), 200); // Через 1 секунду
			}
		});
	});
}

function escapeAndMinifyCSS(css) {
	return css.replace(/\\/g, '\\\\') // Экранируем обратный слэш
		.replace(/\n/g, '') // Удаляем переносы строк (по желанию)
		.replace(/\/\*[\s\S]*?\*\//g, '') // Удаляем комментарии
		.replace(/\s+/g, ' ') // Заменяем множественные пробелы на один
		.trim(); // Удаляем пробелы в начале и конце
}
const addedStyles = new Set();

function customCSS(textCSS) {
	const escapedCSS = escapeAndMinifyCSS(textCSS); // Экранируем CSS
	// Проверяем, был ли уже добавлен этот CSS
	if (!addedStyles.has(escapedCSS)) {
		addedStyles.add(escapedCSS); // Добавляем в множество уникальных стилей
		const styleSheet = document.createElement("style");
		styleSheet.textContent = escapedCSS;
		document.head.appendChild(styleSheet);
	}
}

function createIframe(id) {
	const config = IFRAME_CONFIG[id];
	if (!config) return;
	const iframe = document.createElement('iframe');
	if (config.src && config.src !== "") {
		iframe.src = config.src;
	}
	if (config.srcdoc && config.srcdoc !== "") {
		iframe.srcdoc = config.srcdoc;
	}
	if (config.width && config.width !== "") {
		iframe.width = config.width;
	} else {
		iframe.width = '100%'; // Значение по умолчанию
	}
	if (config.height && config.height !== "") {
		iframe.height = config.height;
	} else {
		iframe.height = '400px'; // Значение по умолчанию
	}
	if (config.name && config.name !== "") {
		iframe.name = config.name;
	}
	if (config.allow && config.allow !== "") {
		iframe.allow = config.allow;
	}
	if (config.referrerpolicy && config.referrerpolicy !== "") {
		iframe.referrerPolicy = config.referrerpolicy;
	}
	if (config.sandbox && config.sandbox !== "") {
		iframe.sandbox = config.sandbox;
	}
	iframe.id = config.id || ''; // id может быть пустым, если не задано
	return iframe;
}
// Функция для увеличения яркости цвета
function brightenColor(color, factor) {
	function getBrightness(r, g, b) {
		return 0.2126 * r + 0.7152 * g + 0.0722 * b;
	}

	function isGray(r, g, b) {
		var maxDiff = 20; // Максимальное допустимое отклонение между RGB для серого
		return Math.abs(r - g) < maxDiff && Math.abs(g - b) < maxDiff && Math.abs(r - b) < maxDiff;
	}

	var rgbValues = color.match(/\d+(\.\d+)?/g);
	var r = parseInt(rgbValues[0], 10);
	var g = parseInt(rgbValues[1], 10);
	var b = parseInt(rgbValues[2], 10);
	var a = rgbValues.length === 4 ? parseFloat(rgbValues[3]) : 1;

	var brightness = getBrightness(r, g, b);

	if (factor === undefined) {
		if (brightness <= 40) {
			factor = 6;
		} else if (brightness <= 180) {
			factor = 4;
		} else {
			factor = 0;
		}
	}

	// Если цвет серый, уменьшаем фактор
	if (isGray(r, g, b)) {
		factor = Math.max(1, factor * 0.50);
	}

	// Добавляем фактор вместо умножения
	r = Math.min(255, r + factor);
	g = Math.min(255, g + factor);
	b = Math.min(255, b + factor);

	return a < 1 ? 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')' : 'rgb(' + r + ', ' + g + ', ' + b + ')';
}

// Функция для подсветки ячеек в таблице при наведении
function applyHighlighting() {
	if (/Mobi|Android/i.test(navigator.userAgent)) {
		return;
	}
	var tables = document.querySelectorAll('.wikitable:not(.no-highlight-table)');
	Array.prototype.forEach.call(tables, function(table) {
		var tbody = table.querySelector('tbody');
		var thead = table.querySelector('thead');
		var noHeader = table.classList.contains('no-header-table');
		if (tbody) {
			// Получаем все строки <tr> внутри первого уровня <tbody>
			var rows = Array.prototype.slice.call(tbody.querySelectorAll('tr')).filter(function(row) {
				// Проверяем, что <tr> находится на первом уровне, и исключаем строки с вложенными таблицами
				return row.parentElement === tbody && !row.querySelector('table');
			});

			// Пропускаем первую строку, если нет <thead> и нет класса 'no-header-table'
			var topLevelRows = (!thead && !noHeader) ? rows.slice(1) : rows;
			var hasInvalidRowspan = false;
			var hasTooManyRowspan = false;

			// Проверка на ошибки в rowspan
			Array.prototype.forEach.call(topLevelRows, function(row) {
				var cells = Array.prototype.slice.call(row.querySelectorAll('td, th')).filter(function(cell) {
					return !cell.classList.contains('mobile');
				});
				var cellCount = cells.length;
				var rowspanCount = cells.filter(function(cell) {
					return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1'; // Игнорируем rowspan="1"
				}).length;

				// Проверка на слишком большое количество rowspan или неправильное расположение rowspan
				if (rowspanCount > 2) {
					hasTooManyRowspan = true;
					return;
				}

				// Проверяем, что ячейки с rowspan находятся по краям строки
				var hasValidRowspanEdge = cells.some(function(cell, index) {
					return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1' && (index === 0 || index === cells.length - 1);
				});

				// Если ячейки с rowspan находятся не по краям
				if (!hasValidRowspanEdge && cells.some(function(cell, index) {
					return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1' && index > 0 && index < cells.length - 1;
				})) {
					hasInvalidRowspan = true;
				}
			});

			// Если есть ошибки в rowspan, выходим
			if (hasTooManyRowspan || hasInvalidRowspan) return;

			// Обработка наведения на строки и ячейки
			Array.prototype.forEach.call(topLevelRows, function(row, rowIndex) {
				var cells = Array.prototype.slice.call(row.querySelectorAll('td, th'));
				// Сохраняем оригинальные стили для каждой ячейки
				var originalStyles = cells.map(function(cell) {
					return {
						backgroundColor: getComputedStyle(cell).backgroundColor,
						color: getComputedStyle(cell).color
					};
				});

				// Наведение на строку (tr)
				row.addEventListener('mouseover', function() {
					highlightRow(row, rowIndex, true);
				});
				row.addEventListener('mouseout', function() {
					highlightRow(row, rowIndex, false);
				});

				// Наведение на ячейки с rowspan
				Array.prototype.forEach.call(cells, function(cell, cellIndex) {
					// Обрабатываем только ячейки с rowspan > 1
					if (cell.hasAttribute('rowspan') && parseInt(cell.getAttribute('rowspan')) > 1) {
						var rowspan = parseInt(cell.getAttribute('rowspan'));

						// Обработка rowspan ячейки
						cell.addEventListener('mouseover', function() {
							// Отключаем обработку строки при наведении на rowspan ячейку
							row.classList.add('highlighted');
							highlightRowspanArea(rowIndex, cellIndex, rowspan, true);
						});

						cell.addEventListener('mouseout', function() {
							// Восстанавливаем состояние строки при уходе курсора
							row.classList.remove('highlighted');
							highlightRowspanArea(rowIndex, cellIndex, rowspan, false);
						});
					}
				});

				// Функция подсветки строки (только текущее tr)
				function highlightRow(row, rowIndex, highlight) {
					if (row.classList.contains('highlighted')) return; // Избегаем повторного применения подсветки
					var rowCells = Array.prototype.slice.call(row.querySelectorAll('td, th'));
					Array.prototype.forEach.call(rowCells, function(cell, cellIndex) {
						// Подсвечиваем только ячейки, не имеющие атрибут rowSpan или с rowspan="1"
						if (!cell.hasAttribute('rowspan') || parseInt(cell.getAttribute('rowspan')) === 1) {
							var cellStyle = getComputedStyle(cell);
							cell.style.setProperty('background-color', highlight ? brightenColor(cellStyle.backgroundColor) :
								originalStyles[cellIndex].backgroundColor, 'important');
							cell.style.setProperty('color', highlight ? brightenColor(cellStyle.color) : originalStyles[cellIndex].color, 'important');
						}
					});
				}

				// Функция подсветки для ячеек с rowspan (подсвечивает все строки, которые охватывает ячейка)
				function highlightRowspanArea(rowIndex, cellIndex, rowspan, highlight) {
					for (var i = 0; i < rowspan; i++) {
						var targetRow = topLevelRows[rowIndex + i];
						if (targetRow) {
							var targetCells = Array.prototype.slice.call(targetRow.querySelectorAll('td, th'));
							// Обработка ячейки в каждой строке, затронутой rowspan
							Array.prototype.forEach.call(targetCells, function(targetCell) {
								var targetCellStyle = getComputedStyle(targetCell);
								// Сохраняем оригинальные стили для каждой ячейки, если подсветка включена
								if (highlight) {
									targetCell.originalBackground = targetCellStyle.backgroundColor;
									targetCell.originalColor = targetCellStyle.color;
								}
								// Применяем подсветку или восстанавливаем оригинальные стили
								targetCell.style.setProperty('background-color', highlight ? brightenColor(targetCellStyle.backgroundColor) :
									targetCell.originalBackground, 'important');
								targetCell.style.setProperty('color', highlight ? brightenColor(targetCellStyle.color) :
									targetCell.originalColor, 'important');
							});
						}
					}
				}
			});
		}
	});
}
// Функция для логики меню, создаваемого модулем CategoryMenu
function initCategorySwitcher() {
	var categories = document.querySelectorAll('.navigation__categories > div');
	var menus = document.querySelectorAll('.navigation__menu-item');
	var contentDivs = document.querySelectorAll('.navigation__content > div');
	var menuItems = document.querySelectorAll('.navigation__menu-item > div');
	var currentCategoryIndex = 0; // Индекс текущей активной категории

	// Генерация ID из текста
	function generateIdFromText(text) {
		return text.trim().replace(/\s+/g, '-').replace(/[^a-zа-яёA-ZА-ЯЁ0-9\-]/g, '');
	}

	// Присвоение ID категориям и пунктам меню
	function assignIds() {
		for (var i = 0; i < categories.length; i++) {
			var category = categories[i];
			category.setAttribute('id', generateIdFromText(category.textContent || category.innerText));

			var menu = menus[i];
			var menuItems = menu.querySelectorAll('div');
			for (var j = 0; j < menuItems.length; j++) {
				menuItems[j].setAttribute('id', generateIdFromText(menuItems[j].textContent || menuItems[j].innerText));
			}
		}
	}

	assignIds(); // Вызов функции для присвоения ID

	// Удаление класса active у всех переданных элементов
	function clearActiveElements(elements) {
		for (var i = 0; i < elements.length; i++) {
			elements[i].classList.remove('active');
		}
	}

	// Переключение категорий
	function switchCategory(index) {
		clearActiveElements(menus);
		clearActiveElements(contentDivs);
		clearActiveElements(categories);

		var selectedCategory = categories[index];
		if (selectedCategory) {
			selectedCategory.classList.add('active');
			var selectedMenu = document.querySelector('.' + selectedCategory.classList[0] + '-menu');
			if (selectedMenu) {
				selectedMenu.classList.add('active');
				switchContent(selectedMenu.querySelector('div')); // Открытие первого пункта меню
			}
		}

		currentCategoryIndex = index;
		updateArrowStates(); // Обновление состояния стрелок
	}

	// Переключение контента в меню
	function switchContent(menuItem) {
		clearActiveElements(menuItems);
		clearActiveElements(contentDivs);

		if (menuItem) {
			var contentClass = menuItem.className + '-content';
			var content = document.querySelector('.' + contentClass);
			if (content) {
				content.classList.add('active');
				menuItem.classList.add('active');
			}
		}
	}

	// Обновление состояния стрелок (активные/неактивные)
	function updateArrowStates() {
		var prevArrow = document.getElementById('prev-category');
		var nextArrow = document.getElementById('next-category');

		prevArrow.classList.toggle('disabled', currentCategoryIndex === 0);
		prevArrow.style.pointerEvents = currentCategoryIndex === 0 ? 'none' : 'auto';

		nextArrow.classList.toggle('disabled', currentCategoryIndex === categories.length - 1);
		nextArrow.style.pointerEvents = currentCategoryIndex === categories.length - 1 ? 'none' : 'auto';
	}

	// Стрелки для переключения категорий
	document.getElementById('prev-category').addEventListener('click', function() {
		if (currentCategoryIndex > 0) {
			switchCategory(--currentCategoryIndex); // Переключение на новую категорию
		}
	});

	document.getElementById('next-category').addEventListener('click', function() {
		if (currentCategoryIndex < categories.length - 1) {
			switchCategory(++currentCategoryIndex); // Переключение на новую категорию
		}
	});

	// Функция для обработки якорей
	function handleAnchorChange() {
		var anchor = window.location.hash.substring(1); // Получаем текущий хеш без символа #
		var decodedAnchor = decodeURIComponent(anchor); // Декодируем хеш
		var found = false;

		// Проверка пунктов меню
		for (var i = 0; i < menuItems.length; i++) {
			if (menuItems[i].id === decodedAnchor) { // Сравниваем с декодированным значением
				var categoryIndex = Array.prototype.indexOf.call(categories, menuItems[i].closest('.navigation__menu-item').previousElementSibling);
				if (categoryIndex !== -1) {
					switchCategory(categoryIndex); // Открываем категорию
					switchContent(menuItems[i]);   // Открываем пункт меню
					found = true; // Якорь найден
				}
				break; // Выход из цикла, если якорь найден
			}
		}

		// Проверка категорий, если якорь не найден в пунктах меню
		if (!found) {
			for (var i = 0; i < categories.length; i++) {
				if (categories[i].id === decodedAnchor) { // Сравниваем с декодированным значением
					switchCategory(i); // Открываем категорию
					found = true; // Якорь найден
					break;
				}
			}
		}
	}

	// Проверяем якорь при изменении URL
	window.addEventListener('hashchange', handleAnchorChange);

	// Инициализация: открытие первой категории и первого пункта
	if (categories.length > 0) {
		assignIds(); // Присвоить ID в начале
		handleAnchorChange(); // Обработка начального якоря

		// Проверка наличия якоря и открытие первой категории только если ID не найден
		if (!window.location.hash) {
			switchCategory(0);
		} else {
			switchCategory(currentCategoryIndex);
		}

		updateArrowStates();
	}

	// Клик по элементам меню
	for (var i = 0; i < menuItems.length; i++) {
		(function(menuItem) {
			menuItem.addEventListener('click', function() {
				switchContent(menuItem); // Переключение контента при клике на пункт меню
				// Убрали изменение хеша при клике
			});
		})(menuItems[i]);
	}

	document.querySelector('.navigation__menu-toggle').addEventListener('click', function() {
		var menu = document.querySelector('.navigation__menu-container');
		menu.classList.toggle('active'); // Переключение класса для показа/скрытия меню
		this.classList.toggle('active'); // Переключение для перемещения кнопки
	});
}
const currentPageTitle = document.title;
$(document).ready(function() {
	var serversStatus = document.querySelectorAll('.serversStatus');
	if (serversStatus.length > 0) {
		updateAllServersInfo();
		// Перезапускать каждую минуту (60000 мс)
		setInterval(updateAllServersInfo, 60000);
	}
	var cssEls = document.querySelectorAll('.customCSS');
	if (cssEls.length > 0) {
		for (var j = 0; j < cssEls.length; j++) {
			const textCSS = cssEls[j].textContent;
			customCSS(textCSS);
		}
	}
	const copyServerConnectionIcon = document.querySelectorAll('.copyServerConnectionIcon');
	copyServerConnectionIcon.forEach(function(icon) {
		icon.addEventListener('click', function() {
			const connectUrl = this.getAttribute('data-connect');
			copyToClipboard(connectUrl);
		});
	});
	copyToClipboard();
	var divs = document.querySelectorAll('.customIFrame');
	if (divs) {
		for (var i = 0; i < divs.length; i++) {
			var div = divs[i];
			var id = div.id;
			var iframe = createIframe(id);
			if (iframe) {
				div.appendChild(iframe);
			}
		}
	}
	var tables = document.querySelectorAll('.wikitable');
	if (tables.length > 0) {
		setTimeout(function() {
			applyHighlighting();
		}, 500);
	}
	if (currentPageTitle.includes("Kerisar")) {
		console.log("Привет, Kerisar!");
		var button = document.createElement("button");
		button.innerText = "Создать архив";
		document.getElementById("archivetest").appendChild(button);
		button.onclick = function() {
			var apiUrl =
				"https://station14.ru/api.php?action=parse&page=Шаблон:Бумажная работа/paperWork.json&prop=text&formatversion=2&format=json";
			fetch(apiUrl).then(function(response) {
				return response.json();
			}).then(function(data) {
				var text = data.parse.text;
				//console.log(text);
				// Извлекаем содержимое между [testarchivestart] и [testarchivestop]
				var startTag = "[testarchivestart]";
				var endTag = "[testarchivestop]";
				var startIndex = text.indexOf(startTag);
				var endIndex = text.indexOf(endTag);
				if (startIndex !== -1 && endIndex !== -1) {
					var extractedContent = text.substring(startIndex + startTag.length, endIndex);
					// Декодируем base64 в бинарные данные
					var binaryString = window.atob(extractedContent);
					var len = binaryString.length;
					var bytes = new Uint8Array(len);
					for (var i = 0; i < len; i++) {
						bytes[i] = binaryString.charCodeAt(i);
					}
					// Создаем Blob из бинарных данных
					var blob = new Blob([bytes], {
						type: "application/zip"
					});
					// Создаем ссылку для скачивания
					var link = document.createElement("a");
					link.href = URL.createObjectURL(blob);
					link.download = "archive.zip"; // Имя файла для скачивания
					link.innerText = "Скачать архив";
					document.getElementById("archivetest").appendChild(link);
				} else {
					alert("Теги [testarchivestart] и [testarchivestop] не найдены.");
				}
			}).catch(function(error) {
				console.error("Ошибка:", error);
			});
		};
	}
	var categoriesExist = document.querySelectorAll('.navigation');
	if (categoriesExist.length > 0) {
		initCategorySwitcher(); 
	}
});
/*WikiEditor/Викификатор*/
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1) {
	mw.loader.load(
		'//ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&action=raw&ctype=text/javascript');
}
var customizeToolbar = function() {
	$('#wpTextbox1').wikiEditor('addToToolbar', {
		'section': 'advanced',
		'group': 'format',
		'tools': {
			'wikify': {
				label: 'Викификатор',
				type: 'button',
				icon: '//upload.wikimedia.org/wikipedia/commons/0/06/Wikify-toolbutton.png',
				action: {
					type: 'callback',
					execute: function(context) {
						Wikify();
					}
				}
			}
		}
	});
};
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1) {
	mw.loader.using('user.options', function() {
		if (mw.user.options.get('usebetatoolbar')) {
			mw.loader.using('ext.wikiEditor.toolbar', function() {
				$(document).ready(customizeToolbar);
			});
		}
	});
}
/**
 * Taken from https://wiki.ss220.space/index.php?title=MediaWiki:Common.js&oldid=35626
 */
/* Variables for interface text used throughout the script, for ease of translating */
var i18n = {
	// Collapsible elements and page loader
	hideText: 'скрыть',
	showText: 'показать',
	// Page loader
	loadErrorTitle: 'Возникла ошибка при загрузке содержимого'
};
var mcw = window.mcw = {};
/* Keep track of delegated events on dynamic content */
mcw.events = {};
/* Fired whenever wiki content is added. (#mw-content-text, live preview, load page, etc.) */
mw.hook('wikipage.content').add(function($wikipageContent) {
	/**
	 * Page loader
	 *
	 * Allows a page to be downloaded and displayed on demand.
	 * Use with Template:LoadPage and Template:LoadBox
	 */
	(function() {
		var $loadPage = $wikipageContent.find('.load-page');
		if (!$loadPage.length) {
			return;
		}
		// We need the spinner to show loading is happening, but we don't want
		// to have a delay while the module downloads, so we'll load this now,
		// regardless of if something is clicked
		mw.loader.load('jquery.spinner');
		// Create button starting with hide text
		// Will be changed to the show text while calculating the maximum button size
		var $buttonTemplate = $('<span>').addClass('mw-editsection-like load-page-button').append('[ ', $(
			'<span>').addClass('jslink').text(i18n.hideText), ' ]');
		var extractList = function($contentContainer, listClass) {
			var $content = $contentContainer.find('.mw-parser-output > ul > li > ul').children(
				':not(.nbttree-inherited)');
			if (listClass) {
				$content.addClass(listClass);
			}
			return $content;
		};
		$loadPage.each(function() {
			var $body = $(this);
			var page = $body.data('page');
			if (!page) {
				return;
			}
			var template = $body.data('template');
			var treeview = $body.data('treeview');
			var treeviewClass = $body.data('treeviewclass');
			var $heading;
			var $contentContainer;
			var $content;
			var $button = $buttonTemplate.clone();
			var $buttonLink = $button.find('.jslink');
			if (treeview) {
				$heading = $body;
				$contentContainer = $('<div>');
			} else {
				$heading = $body.children().first();
				$contentContainer = $body.find('.load-page-content');
			}
			// Add the button
			$heading.append($button);
			// Move the edit button to the right spot
			$contentContainer.find('.mw-editsection, .mw-editsection-like').insertAfter($button);
			// Find max button width, and set its min-width to it
			var hideWidth = $button.width();
			$buttonLink.text(i18n.showText);
			var showWidth = $button.width();
			if (hideWidth !== showWidth) {
				$button.css('min-width', hideWidth > showWidth ? hideWidth : showWidth);
			}
			$buttonLink.click(function() {
				if ($body.hasClass('pageloader-contentloaded')) {
					if ($buttonLink.text() === i18n.showText) {
						if (treeview) {
							$content.insertAfter($body);
						} else {
							$contentContainer.show();
						}
						$buttonLink.text(i18n.hideText);
					} else {
						if (treeview) {
							$content.detach();
						} else {
							$contentContainer.hide();
						}
						$buttonLink.text(i18n.showText);
					}
					return;
				}
				// See if this was loaded elsewhere before making a request
				var gotContent;
				$('.pageloader-contentloaded').each(function() {
					var $fLoader = $(this);
					if ($fLoader.data('page') === page && $fLoader.data('pageloader-content')) {
						$contentContainer.html($fLoader.data('pageloader-content')).removeClass('noscript');
						mw.hook('wikipage.content').fire($contentContainer);
						if (treeview) {
							$body.find('.noscript').remove();
							$content = extractList($contentContainer, treeviewClass);
							$content.insertAfter($body);
						}
						$buttonLink.text(i18n.hideText);
						$body.addClass('pageloader-contentloaded');
						gotContent = true;
						return false;
					}
				});
				if (gotContent) {
					return;
				}
				// Just in-case the spinner module is still not ready yet
				var $spinner = $();
				mw.loader.using('jquery.spinner', function() {
					// $spinner will be false if the content somehow loaded before the module did
					if ($spinner) {
						$spinner = $.createSpinner().addClass('mw-editsection-like').css('min-width', $button.css(
							'min-width'));
						$button.hide().after($spinner);
					}
				});
				var requestData = {
					action: 'parse',
					prop: 'text'
				};
				if (template) {
					requestData.page = page;
				} else {
					requestData.title = mw.config.get('wgPageName');
					requestData.text = '{' + '{:' + page + '}}';
				}
				new mw.Api().get(requestData).done(function(data) {
					var html = data.parse.text['*'];
					$contentContainer.html(html).removeClass('noscript');
					// Resolve self-links
					if (template) {
						var curPage = '/' + mw.config.get('wgPageName');
						$contentContainer.find('a').each(function() {
							var $link = $(this);
							if ($link.attr('href') === curPage) {
								$link.replaceWith($('<strong>').addClass('selflink').append($link.contents()));
							}
						});
						html = $contentContainer.html();
					}
					$body.data('pageloader-content', html);
					// Fire content hook on the new content, running all this stuff again and more :)
					mw.hook('wikipage.content').fire($contentContainer);
					if (treeview) {
						$body.find('.noscript').remove();
						$content = extractList($contentContainer, treeviewClass);
						$content.insertAfter($body);
					}
					$spinner.remove();
					$spinner = false;
					$buttonLink.text(i18n.hideText);
					$button.show();
					$body.addClass('pageloader-contentloaded');
				}).fail(function(_, error) {
					$spinner.remove();
					$spinner = false;
					$button.show();
					var errorText = '';
					if (error.textStatus) {
						errorText = error.textStatus;
					} else if (error.error) {
						errorText = error.error.info;
					}
					mw.notify(errorText, {
						title: i18n.loadErrorTitle,
						autoHide: false
					});
				});
			});
		});
	}());
	/**
	 * Element animator
	 *
	 * Will cycle the active class on any child elements
	 * within an element with the animated class.
	 */
	(function() {
		if (!mcw.animate) {
			mcw.animate = setInterval(function() {
				$('.animated').each(function() {
					var $elem = $(this);
					var $current = $elem.children('.active');
					var $next = $current.nextAll(':not(.skip):first');
					// Loop back to the start
					if (!$next.length) {
						$next = $elem.children(':not(.skip):first');
					}
					$current.removeClass('active');
					$next.addClass('active');
				});
			}, 2000);
		}
	}());
});
// SS220 import end