document.addEventListener("DOMContentLoaded", () => { document.body.addEventListener('click', async (e) => { const link = e.target.closest('a'); if (!link) return; // Если мы находимся внутри фрейма/объекта (например, на странице карты), // перенаправляем родительское окно. if (window !== window.top) { e.preventDefault(); window.top.location.href = link.href; return; } const href = link.getAttribute('href'); // Отсеиваем внешние ссылки, пустые ссылки и ссылки с target="_blank" if (!href || href.startsWith('http') || href.startsWith('//') || href.startsWith('minecraft://') || href.startsWith('mailto:') || link.getAttribute('target') === '_blank') { return; } e.preventDefault(); // Закрываем мобильное меню при навигации const menuToggle = document.getElementById('menutog'); if (menuToggle && menuToggle.checked) { menuToggle.checked = false; const headerMenu = document.querySelector('.Header_menu'); if (headerMenu) headerMenu.style.display = 'none'; const hdr = document.querySelector('.hdr'); if (hdr) hdr.style.borderRadius = '25px'; } // Меняем URL без перезагрузки window.history.pushState({}, '', href); await loadPage(href); }); window.addEventListener('popstate', async () => { await loadPage(window.location.pathname + window.location.search); }); async function loadPage(url) { const contentCenter = document.querySelector('.content_center'); if (contentCenter) contentCenter.style.opacity = '0.5'; try { const response = await fetch(url); if (!response.ok) { window.location.href = url; return; } const html = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); document.title = doc.title; const newContent = doc.querySelector('.content_center'); if (newContent && contentCenter) { contentCenter.innerHTML = newContent.innerHTML; // Добавляем новые скрипты и стили, если они появились updateHead(doc); // Выполняем инлайн-скрипты внутри content_center executeScripts(contentCenter); // Если мы вернулись на главную и загружены скрипты статуса, перезапрашиваем их if (url === '/' || url.endsWith('/')) { if (typeof updateServerStatus === 'function') updateServerStatus(); if (typeof loadAllowlist === 'function') loadAllowlist(); } // Плавное появление contentCenter.style.transition = 'opacity 0.2s'; contentCenter.style.opacity = '1'; // Отправляем хит в Яндекс Метрику, если она подключена if (typeof ym !== 'undefined') { ym(106164940, 'hit', url); } } else { window.location.href = url; } } catch (err) { console.error('PJAX Error:', err); window.location.href = url; } } function updateHead(newDoc) { const currentHead = document.head; const newScripts = newDoc.querySelectorAll('head script[src]'); const newLinks = newDoc.querySelectorAll('head link[rel="stylesheet"]'); newLinks.forEach(newLink => { const href = newLink.getAttribute('href'); if (!currentHead.querySelector(`link[href="${href}"]`)) { const linkObj = document.createElement('link'); linkObj.rel = 'stylesheet'; linkObj.href = href; currentHead.appendChild(linkObj); } }); newScripts.forEach(newScript => { const src = newScript.getAttribute('src'); if (!currentHead.querySelector(`script[src="${src}"]`)) { const scriptObj = document.createElement('script'); scriptObj.src = src; scriptObj.defer = newScript.hasAttribute('defer'); currentHead.appendChild(scriptObj); } }); } function executeScripts(container) { const scripts = container.querySelectorAll('script'); scripts.forEach(oldScript => { const newScript = document.createElement('script'); Array.from(oldScript.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value)); if (oldScript.innerHTML) { newScript.appendChild(document.createTextNode(oldScript.innerHTML)); } oldScript.parentNode.replaceChild(newScript, oldScript); }); } });