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

Материал из Space Station 14 Вики
м (iframe контролируемы и задаются конфигом (глобальная переменная))
мНет описания правки
 
(не показано 307 промежуточных версий 2 участников)
Строка 1: Строка 1:
const IFRAME_CONFIG = {
const IFRAME_CONFIG = {
    iframe1: {
iframe1: {
        src: 'https://example.com',
src: 'https://example.com',
        srcdoc: '',
srcdoc: '',
        width: '600',
width: '600',
        height: '400',
height: '400',
        name: 'iframe1',
name: 'iframe1',
        allow: 'clipboard-write',
allow: 'clipboard-write',
        referrerpolicy: 'no-referrer',
referrerpolicy: 'no-referrer',
        sandbox: 'allow-same-origin',
sandbox: 'allow-same-origin',
        id: 'iframe1'
id: 'iframe1'
    },
},
    iframe2: {
iframeMapRender: {
        src: '',
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/panzoom@4.5.1/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>',
        srcdoc: '<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Bootstrap demo</title><link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script></head><body><div class="accordion" id="accordionExample"><div class="accordion-item"><h2 class="accordion-header"><button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> Accordion Item #1 </button></h2><div id="collapseOne" class="accordion-collapse collapse show" data-bs-parent="#accordionExample"><div class="accordion-body"><strong>This is the first item»s accordion body.</strong> It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It»s also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow. </div></div></div><div class="accordion-item"><h2 class="accordion-header"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"> Accordion Item #2 </button></h2><div id="collapseTwo" class="accordion-collapse collapse" data-bs-parent="#accordionExample"><div class="accordion-body"><strong>This is the second item»s accordion body.</strong> It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It»s also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow. </div></div></div><div class="accordion-item"><h2 class="accordion-header"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree"> Accordion Item #3 </button></h2><div id="collapseThree" class="accordion-collapse collapse" data-bs-parent="#accordionExample"><div class="accordion-body"><strong>This is the third item»s accordion body.</strong> It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It»s also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow. </div></div></div></div><a href="javascript:(function(){ var name = prompt(«Введите ваше имя»); alert(«Привет, « + name); })();">Click me</a><button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop"> Launch static backdrop modal </button><div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h1 class="modal-title fs-5" id="staticBackdropLabel">Modal title</h1><button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></div><div class="modal-body"> ... </div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button><button type="button" class="btn btn-primary">Understood</button></div></div></div></div></body></html>',
width: '100%',
        width: '600',
height: '100%',
        height: '400',
name: 'iframeMapRender',
        name: 'iframe2',
id: 'iframeMapRender'
        allow: 'clipboard-write',
},
        referrerpolicy: 'no-referrer',
iframeSkillsTableRed: {
        sandbox: 'allow-same-origin',
src: 'https://docs.google.com/spreadsheets/d/1AvfEvRdw98iezJk2i0DVJpTgoJu2sgLnhMK9fp-LqFk/edit?gid=189048440#gid=189048440',
        id: 'iframe2'
width: '100%',
    }
height: '1900px',
id: "iframeSkillsTableRed"
},
};
};
const currentURL = window.location.href;
const currentURL = window.location.href;
const serversStatus = [{
const serversStatus = [{
  name: "server-main",
name: "server-main",
  connect: "https://game2.station14.ru/main/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/main/server/status",
  serverconnect: "game2.station14.ru/main/server"
serverconnect: "game2.station14.ru/main/server"
}, {
}, {
  name: "server-nova",
name: "server-nova",
  connect: "https://game2.station14.ru/nova/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/nova/server/status",
  serverconnect: "game2.station14.ru/nova/server"
serverconnect: "game2.station14.ru/nova/server"
}, {
}, {
  name: "server-athara",
name: "server-athara",
  connect: "https://game2.station14.ru/athara/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/athara/server/status",
  serverconnect: "game2.station14.ru/athara/server"
serverconnect: "game2.station14.ru/athara/server"
}, {
}, {
  name: "server-solaris",
name: "server-solaris",
  connect: "https://game2.station14.ru/solaris/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/solaris/server/status",
  serverconnect: "game2.station14.ru/solaris/server"
serverconnect: "game2.station14.ru/solaris/server"
}, {
}, {
  name: "server-echo",
name: "server-echo",
  connect: "https://game2.station14.ru/echo/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/echo/server/status",
  serverconnect: "game2.station14.ru/echo/server"
serverconnect: "game2.station14.ru/echo/server"
}, {
}, {
  name: "server-elysium",
name: "server-elysium",
  connect: "https://game2.station14.ru/elysium/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/elysium/server/status",
  serverconnect: "game2.station14.ru/elysium/server"
serverconnect: "game2.station14.ru/elysium/server"
}, {
}, {
  name: "server-nebula",
name: "server-nebula",
  connect: "https://game2.station14.ru/nebula/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/nebula/server/status",
  serverconnect: "game2.station14.ru/nebula/server"
serverconnect: "game2.station14.ru/nebula/server"
}, {
}, {
  name: "server-wl",
name: "server-wl",
  connect: "https://game2.station14.ru/wl/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game2.station14.ru/wl/server/status",
  serverconnect: "game2.station14.ru/wl/server"
serverconnect: "game2.station14.ru/wl/server"
}, {
}, {
  name: "server-frontier",
name: "server-frontier",
  connect: "https://api.codetabs.com/v1/proxy/?quest=https://arles.station14.ru/frontier-main/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://arles.station14.ru/frontier-main/server/status",
  serverconnect: "arles.station14.ru/frontier-main/server"
serverconnect: "arles.station14.ru/frontier-main/server"
}, {
}, {
  name: "server-fallout",
name: "server-fallout",
  connect: "https://api.codetabs.com/v1/proxy/?quest=http://188.92.78.98:1221/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=http://188.92.78.98:1221/status",
  serverconnect: "188.92.78.98:1221"
serverconnect: "188.92.78.98:1221"
}, {
}, {
  name: "server-marines",
name: "server-marines",
  connect: "https://game1.station14.ru/marines-main/server/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=https://game1.station14.ru/marines-main/server/status",
  serverconnect: "game1.station14.ru/marines-main/server"
serverconnect: "game1.station14.ru/marines-main/server"
}, {
}, {
  name: "server-stalker",
name: "server-stalker",
  connect: "https://api.codetabs.com/v1/proxy/?quest=https://game.stalkers14.xyz/status",
connect: "https://api.codetabs.com/v1/proxy/?quest=http://game.stalkers14.xyz/status",
  serverconnect: "game.stalkers14.xyz"
serverconnect: "game.stalkers14.xyz"
}];
}];


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


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


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


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


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


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


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


function copyToClipboard(connectUrl) {
function copyToClipboard(connectUrl) {
  const copyIcons = document.querySelectorAll('.copy-icon');
const copyIcons = document.querySelectorAll('.copy-icon');
  copyIcons.forEach(function(icon) {
copyIcons.forEach(function(icon) {
    icon.addEventListener('click', function() {
icon.addEventListener('click', function() {
      // Находим предыдущий элемент
// Находим предыдущий элемент
      const previousElement = this.previousElementSibling;
const previousElement = this.previousElementSibling;
      if (previousElement) {
if (previousElement) {
        // Получаем текстовое содержимое
// Получаем текстовое содержимое
        const textToCopy = previousElement.textContent;
const textToCopy = previousElement.textContent;
        const tempInput = document.createElement('input');
const tempInput = document.createElement('input');
        tempInput.value = textToCopy;
tempInput.value = textToCopy;
        document.body.appendChild(tempInput);
document.body.appendChild(tempInput);
        tempInput.select();
tempInput.select();
        document.execCommand('copy');
document.execCommand('copy');
        document.body.removeChild(tempInput);
document.body.removeChild(tempInput);
        // Визуальный эффект
// Визуальный эффект
        this.style.opacity = '0.5'; // Сменяем прозрачность
this.style.opacity = '0.5'; // Сменяем прозрачность
        setTimeout(function() {
setTimeout(function() {
          this.style.opacity = '1'; // Возвращаем прозрачность
this.style.opacity = '1'; // Возвращаем прозрачность
        }.bind(this), 200); // Через 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) {
function customCSS(textCSS) {
  const styleSheet = document.createElement("style");
const escapedCSS = escapeAndMinifyCSS(textCSS); // Экранируем CSS
  styleSheet.textContent = textCSS;
// Проверяем, был ли уже добавлен этот CSS
  //console.log(textCSS);
if (!addedStyles.has(escapedCSS)) {
  document.head.appendChild(styleSheet);
addedStyles.add(escapedCSS); // Добавляем в множество уникальных стилей
const styleSheet = document.createElement("style");
styleSheet.textContent = escapedCSS;
document.head.appendChild(styleSheet);
}
}
}


function createIframe(id) {
function createIframe(id) {
    const config = IFRAME_CONFIG[id];
const config = IFRAME_CONFIG[id];
    if (!config) return;
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;
}


    const iframe = document.createElement('iframe');
function isGray(r, g, b) {
    iframe.src = config.src || '';
var maxDiff = 20; // Максимальное допустимое отклонение между RGB для серого
    iframe.srcdoc = config.src || '';
return Math.abs(r - g) < maxDiff && Math.abs(g - b) < maxDiff && Math.abs(r - b) < maxDiff;
    iframe.width = config.width || '100%';
}
    iframe.height = config.height || '100%';
    iframe.name = config.name || '';
    iframe.allow = config.allow || '';
    iframe.referrerPolicy = config.referrerpolicy || '';
    iframe.sandbox = config.sandbox || '';
    iframe.id = config.id || '';


    return iframe;
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() {
$(document).ready(function() {
  var serversStatus = document.querySelectorAll('.serversStatus');
var serversStatus = document.querySelectorAll('.serversStatus');
  if (serversStatus.length > 0) {
if (serversStatus.length > 0) {
    updateAllServersInfo();
updateAllServersInfo();
    // Перезапускать каждую минуту (60000 мс)
// Перезапускать каждую минуту (60000 мс)
    setInterval(updateAllServersInfo, 60000);
setInterval(updateAllServersInfo, 60000);
  }
}
 
var cssEls = document.querySelectorAll('.customCSS');
  document.querySelectorAll('.customIFrame').forEach(div => {
if (cssEls.length > 0) {
    const id = div.id;
for (var j = 0; j < cssEls.length; j++) {
    const iframe = createIframe(id);
const textCSS = cssEls[j].textContent;
    if (iframe) {
customCSS(textCSS);
        div.appendChild(iframe);
}
    }
}
  });
const copyServerConnectionIcon = document.querySelectorAll('.copyServerConnectionIcon');
 
copyServerConnectionIcon.forEach(function(icon) {
  var cssEls = document.querySelectorAll('.customCSS');
icon.addEventListener('click', function() {
  if (cssEls.length > 0) {
const connectUrl = this.getAttribute('data-connect');
    for (var i = 0; i < cssEls.length; i++) {
copyToClipboard(connectUrl);
      const textCSS = cssEls[i].textContent;
});
      //console.log(textCSS);
});
      customCSS(textCSS);
copyToClipboard();
    }
var divs = document.querySelectorAll('.customIFrame');
  }
if (divs) {
  const copyServerConnectionIcon = document.querySelectorAll(
for (var i = 0; i < divs.length; i++) {
    '.copyServerConnectionIcon');
var div = divs[i];
  copyServerConnectionIcon.forEach(function(icon) {
var id = div.id;
    icon.addEventListener('click', function() {
var iframe = createIframe(id);
      const connectUrl = this.getAttribute('data-connect');
if (iframe) {
      copyToClipboard(connectUrl);
div.appendChild(iframe);
    });
}
  });
}
  copyToClipboard();
}
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/Викификатор*/
/*WikiEditor/Викификатор*/
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1) {
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1) {
  mw.loader.load(
mw.loader.load(
    '//ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&action=raw&ctype=text/javascript'
'//ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&action=raw&ctype=text/javascript');
  );
}
}
var customizeToolbar = function() {
var customizeToolbar = function() {
  $('#wpTextbox1').wikiEditor('addToToolbar', {
$('#wpTextbox1').wikiEditor('addToToolbar', {
    'section': 'advanced',
'section': 'advanced',
    'group': 'format',
'group': 'format',
    'tools': {
'tools': {
      'wikify': {
'wikify': {
        label: 'Викификатор',
label: 'Викификатор',
        type: 'button',
type: 'button',
        icon: '//upload.wikimedia.org/wikipedia/commons/0/06/Wikify-toolbutton.png',
icon: '//upload.wikimedia.org/wikipedia/commons/0/06/Wikify-toolbutton.png',
        action: {
action: {
          type: 'callback',
type: 'callback',
          execute: function(context) {
execute: function(context) {
            Wikify();
Wikify();
          }
}
        }
}
      }
}
    }
}
  });
});
};
};
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1) {
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1) {
  mw.loader.using('user.options', function() {
mw.loader.using('user.options', function() {
    if (mw.user.options.get('usebetatoolbar')) {
if (mw.user.options.get('usebetatoolbar')) {
      mw.loader.using('ext.wikiEditor.toolbar', function() {
mw.loader.using('ext.wikiEditor.toolbar', function() {
        $(document).ready(customizeToolbar);
$(document).ready(customizeToolbar);
      });
});
    }
}
  });
});
}
}
/**
/**
Строка 328: Строка 743:
/* Variables for interface text used throughout the script, for ease of translating */
/* Variables for interface text used throughout the script, for ease of translating */
var i18n = {
var i18n = {
  // Collapsible elements and page loader
// Collapsible elements and page loader
  hideText: 'скрыть',
hideText: 'скрыть',
  showText: 'показать',
showText: 'показать',
  // Page loader
// Page loader
  loadErrorTitle: 'Возникла ошибка при загрузке содержимого'
loadErrorTitle: 'Возникла ошибка при загрузке содержимого'
};
};
var mcw = window.mcw = {};
var mcw = window.mcw = {};
Строка 339: Строка 754:
/* Fired whenever wiki content is added. (#mw-content-text, live preview, load page, etc.) */
/* Fired whenever wiki content is added. (#mw-content-text, live preview, load page, etc.) */
mw.hook('wikipage.content').add(function($wikipageContent) {
mw.hook('wikipage.content').add(function($wikipageContent) {
  /**
/**
  * Page loader
* Page loader
  *
*
  * Allows a page to be downloaded and displayed on demand.
* Allows a page to be downloaded and displayed on demand.
  * Use with Template:LoadPage and Template:LoadBox
* Use with Template:LoadPage and Template:LoadBox
  */
*/
  (function() {
(function() {
    var $loadPage = $wikipageContent.find('.load-page');
var $loadPage = $wikipageContent.find('.load-page');
    if (!$loadPage.length) {
if (!$loadPage.length) {
      return;
return;
    }
}
    // We need the spinner to show loading is happening, but we don't want
// 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,
// to have a delay while the module downloads, so we'll load this now,
    // regardless of if something is clicked
// regardless of if something is clicked
    mw.loader.load('jquery.spinner');
mw.loader.load('jquery.spinner');
    // Create button starting with hide text
// Create button starting with hide text
    // Will be changed to the show text while calculating the maximum button size
// Will be changed to the show text while calculating the maximum button size
    var $buttonTemplate = $('<span>').addClass(
var $buttonTemplate = $('<span>').addClass('mw-editsection-like load-page-button').append('[ ', $(
      'mw-editsection-like load-page-button').append('[ ', $('<span>').addClass(
'<span>').addClass('jslink').text(i18n.hideText), ' ]');
      'jslink').text(i18n.hideText), ' ]');
var extractList = function($contentContainer, listClass) {
    var extractList = function($contentContainer, listClass) {
var $content = $contentContainer.find('.mw-parser-output > ul > li > ul').children(
      var $content = $contentContainer.find('.mw-parser-output > ul > li > ul')
':not(.nbttree-inherited)');
        .children(':not(.nbttree-inherited)');
if (listClass) {
      if (listClass) {
$content.addClass(listClass);
        $content.addClass(listClass);
}
      }
return $content;
      return $content;
};
    };
$loadPage.each(function() {
    $loadPage.each(function() {
var $body = $(this);
      var $body = $(this);
var page = $body.data('page');
      var page = $body.data('page');
if (!page) {
      if (!page) {
return;
        return;
}
      }
var template = $body.data('template');
      var template = $body.data('template');
var treeview = $body.data('treeview');
      var treeview = $body.data('treeview');
var treeviewClass = $body.data('treeviewclass');
      var treeviewClass = $body.data('treeviewclass');
var $heading;
      var $heading;
var $contentContainer;
      var $contentContainer;
var $content;
      var $content;
var $button = $buttonTemplate.clone();
      var $button = $buttonTemplate.clone();
var $buttonLink = $button.find('.jslink');
      var $buttonLink = $button.find('.jslink');
if (treeview) {
      if (treeview) {
$heading = $body;
        $heading = $body;
$contentContainer = $('<div>');
        $contentContainer = $('<div>');
} else {
      } else {
$heading = $body.children().first();
        $heading = $body.children().first();
$contentContainer = $body.find('.load-page-content');
        $contentContainer = $body.find('.load-page-content');
}
      }
// Add the button
      // Add the button
$heading.append($button);
      $heading.append($button);
// Move the edit button to the right spot
      // Move the edit button to the right spot
$contentContainer.find('.mw-editsection, .mw-editsection-like').insertAfter($button);
      $contentContainer.find('.mw-editsection, .mw-editsection-like').insertAfter(
// Find max button width, and set its min-width to it
        $button);
var hideWidth = $button.width();
      // Find max button width, and set its min-width to it
$buttonLink.text(i18n.showText);
      var hideWidth = $button.width();
var showWidth = $button.width();
      $buttonLink.text(i18n.showText);
if (hideWidth !== showWidth) {
      var showWidth = $button.width();
$button.css('min-width', hideWidth > showWidth ? hideWidth : showWidth);
      if (hideWidth !== showWidth) {
}
        $button.css('min-width', hideWidth > showWidth ? hideWidth : showWidth);
$buttonLink.click(function() {
      }
if ($body.hasClass('pageloader-contentloaded')) {
      $buttonLink.click(function() {
if ($buttonLink.text() === i18n.showText) {
        if ($body.hasClass('pageloader-contentloaded')) {
if (treeview) {
          if ($buttonLink.text() === i18n.showText) {
$content.insertAfter($body);
            if (treeview) {
} else {
              $content.insertAfter($body);
$contentContainer.show();
            } else {
}
              $contentContainer.show();
$buttonLink.text(i18n.hideText);
            }
} else {
            $buttonLink.text(i18n.hideText);
if (treeview) {
          } else {
$content.detach();
            if (treeview) {
} else {
              $content.detach();
$contentContainer.hide();
            } else {
}
              $contentContainer.hide();
$buttonLink.text(i18n.showText);
            }
}
            $buttonLink.text(i18n.showText);
return;
          }
}
          return;
// See if this was loaded elsewhere before making a request
        }
var gotContent;
        // See if this was loaded elsewhere before making a request
$('.pageloader-contentloaded').each(function() {
        var gotContent;
var $fLoader = $(this);
        $('.pageloader-contentloaded').each(function() {
if ($fLoader.data('page') === page && $fLoader.data('pageloader-content')) {
          var $fLoader = $(this);
$contentContainer.html($fLoader.data('pageloader-content')).removeClass('noscript');
          if ($fLoader.data('page') === page && $fLoader.data(
mw.hook('wikipage.content').fire($contentContainer);
              'pageloader-content')) {
if (treeview) {
            $contentContainer.html($fLoader.data('pageloader-content')).removeClass(
$body.find('.noscript').remove();
              'noscript');
$content = extractList($contentContainer, treeviewClass);
            mw.hook('wikipage.content').fire($contentContainer);
$content.insertAfter($body);
            if (treeview) {
}
              $body.find('.noscript').remove();
$buttonLink.text(i18n.hideText);
              $content = extractList($contentContainer, treeviewClass);
$body.addClass('pageloader-contentloaded');
              $content.insertAfter($body);
gotContent = true;
            }
return false;
            $buttonLink.text(i18n.hideText);
}
            $body.addClass('pageloader-contentloaded');
});
            gotContent = true;
if (gotContent) {
            return false;
return;
          }
}
        });
// Just in-case the spinner module is still not ready yet
        if (gotContent) {
var $spinner = $();
          return;
mw.loader.using('jquery.spinner', function() {
        }
// $spinner will be false if the content somehow loaded before the module did
        // Just in-case the spinner module is still not ready yet
if ($spinner) {
        var $spinner = $();
$spinner = $.createSpinner().addClass('mw-editsection-like').css('min-width', $button.css(
        mw.loader.using('jquery.spinner', function() {
'min-width'));
          // $spinner will be false if the content somehow loaded before the module did
$button.hide().after($spinner);
          if ($spinner) {
}
            $spinner = $.createSpinner().addClass('mw-editsection-like').css(
});
              'min-width', $button.css('min-width'));
var requestData = {
            $button.hide().after($spinner);
action: 'parse',
          }
prop: 'text'
        });
};
        var requestData = {
if (template) {
          action: 'parse',
requestData.page = page;
          prop: 'text'
} else {
        };
requestData.title = mw.config.get('wgPageName');
        if (template) {
requestData.text = '{' + '{:' + page + '}}';
          requestData.page = page;
}
        } else {
new mw.Api().get(requestData).done(function(data) {
          requestData.title = mw.config.get('wgPageName');
var html = data.parse.text['*'];
          requestData.text = '{' + '{:' + page + '}}';
$contentContainer.html(html).removeClass('noscript');
        }
// Resolve self-links
        new mw.Api().get(requestData).done(function(data) {
if (template) {
          var html = data.parse.text['*'];
var curPage = '/' + mw.config.get('wgPageName');
          $contentContainer.html(html).removeClass('noscript');
$contentContainer.find('a').each(function() {
          // Resolve self-links
var $link = $(this);
          if (template) {
if ($link.attr('href') === curPage) {
            var curPage = '/' + mw.config.get('wgPageName');
$link.replaceWith($('<strong>').addClass('selflink').append($link.contents()));
            $contentContainer.find('a').each(function() {
}
              var $link = $(this);
});
              if ($link.attr('href') === curPage) {
html = $contentContainer.html();
                $link.replaceWith($('<strong>').addClass('selflink').append(
}
                  $link.contents()));
$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);
            html = $contentContainer.html();
if (treeview) {
          }
$body.find('.noscript').remove();
          $body.data('pageloader-content', html);
$content = extractList($contentContainer, treeviewClass);
          // Fire content hook on the new content, running all this stuff again and more :)
$content.insertAfter($body);
          mw.hook('wikipage.content').fire($contentContainer);
}
          if (treeview) {
$spinner.remove();
            $body.find('.noscript').remove();
$spinner = false;
            $content = extractList($contentContainer, treeviewClass);
$buttonLink.text(i18n.hideText);
            $content.insertAfter($body);
$button.show();
          }
$body.addClass('pageloader-contentloaded');
          $spinner.remove();
}).fail(function(_, error) {
          $spinner = false;
$spinner.remove();
          $buttonLink.text(i18n.hideText);
$spinner = false;
          $button.show();
$button.show();
          $body.addClass('pageloader-contentloaded');
var errorText = '';
        }).fail(function(_, error) {
if (error.textStatus) {
          $spinner.remove();
errorText = error.textStatus;
          $spinner = false;
} else if (error.error) {
          $button.show();
errorText = error.error.info;
          var errorText = '';
}
          if (error.textStatus) {
mw.notify(errorText, {
            errorText = error.textStatus;
title: i18n.loadErrorTitle,
          } else if (error.error) {
autoHide: false
            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.
  /**
*/
  * Element animator
(function() {
  *
if (!mcw.animate) {
  * Will cycle the active class on any child elements
mcw.animate = setInterval(function() {
  * within an element with the animated class.
$('.animated').each(function() {
  */
var $elem = $(this);
  (function() {
var $current = $elem.children('.active');
    if (!mcw.animate) {
var $next = $current.nextAll(':not(.skip):first');
      mcw.animate = setInterval(function() {
// Loop back to the start
        $('.animated').each(function() {
if (!$next.length) {
          var $elem = $(this);
$next = $elem.children(':not(.skip):first');
          var $current = $elem.children('.active');
}
          var $next = $current.nextAll(':not(.skip):first');
$current.removeClass('active');
          // Loop back to the start
$next.addClass('active');
          if (!$next.length) {
});
            $next = $elem.children(':not(.skip):first');
}, 2000);
          }
}
          $current.removeClass('active');
}());
          $next.addClass('active');
        });
      }, 2000);
    }
  }());
});
});
// SS220 import end
// 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