<script>
(function () {
if (location.protocol !== 'https:') return;
if (/messages\.php|inbox|outbox|sendmsg|privmsg/i.test(location.href)) return;
function rewriteSrc(el) {
if (el.src && el.src.startsWith('http://')) el.src = el.src.replace(/^http:/, 'https:');
if (el.getAttribute('srcset')) el.setAttribute('srcset', el.getAttribute('srcset').replace(/http:\/\//g, 'https://'));
}
const mo = new MutationObserver(function (mutations) {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (node.nodeType !== 1) continue;
if (node.tagName === 'IMG') rewriteSrc(node);
node.querySelectorAll?.('img, source, iframe, video source, audio source').forEach(rewriteSrc);
}
if (m.type === 'attributes' && m.attributeName === 'src') rewriteSrc(m.target);
}
});
if (document.documentElement) mo.observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['src'] });
document.addEventListener('DOMContentLoaded', function () {
if (/messages\.php|inbox|outbox|sendmsg|privmsg/i.test(location.href)) return;
document.querySelectorAll('img[src^="http://"], source[src^="http://"], iframe[src^="http://"]').forEach(rewriteSrc);
}, { once: true });
})();
document.addEventListener("DOMContentLoaded", function () {
const isMSG = /messages\.php|inbox|outbox|sendmsg|privmsg/i.test(location.href);
if (isMSG) { fixAllMixedContent(); ChangeAll(); applyFontSize(); return; }
const CONFIG = {
observerDelay: 0,
enableIndexNickColoring: true,
replacements: {
profileElements: [
['.pl-email.profile', 'Профиль', '\u{1F464}Профиль'],
['.pl-email.email', 'E-mail', '\u{1F4E7}Mail'],
['.pl-email.pm', 'ЛС', '\u{2709}\u{FE0F}\u00A0ЛС'],
['.pa-ip', 'IP', '\u{1F5A7} IP'],
['.pl-website.website', 'Вебсайт', '\u{1F310}']
],
postButtons: [
['.pl-edit a', 'Редактировать', '\u{270D}\u{FE0F}\u00A0Редактировать'],
['.pl-delete a', 'Удалить', '\u{274C}\u00A0Удалить'],
['.pl-quote a', 'Цитировать', '\u{1F4AC}\u00A0Цитировать'],
['.pl-reply a', 'Ответить', '\u{21A9}\u{FE0F}\u00A0Ответить'],
['.pa-posts', 'Сообщений', '\u{1F4E8} Сообщений'],
],
miniProfile: [
['.pa-sex', 'Пол', '\u{26A7}\u{FE0F} Пол'],
['.pa-fld3', 'Создано тем', '\u{2795} Создано тем'],
['.fld-name', 'Откуда', '\u{1F9ED} Откуда'],
['.pa-respect', 'Уважение', '\u{2B50} Рейтинг']
]
},
miniProfileSelectors: ["li.pa-title","li.pa-fld1"],
groupColors: { 1: ['#008080','#a1b2cc'], 2: ['#993232','#d15f13'], 3: ['#000000','#B0B0B0'], 4: ['#072387','#5869a3'] },
miniProfileColors: {
"Модератор": { color: ['#38761d','#6abd46'], groups: [2] },
"Администратор": { color: ['#5c1eba','#a1b2cc'], groups: [1] },
"The Wizard of the Realm": { color: ['#2986cc','#a1b2cc'], groups: [1] }
}
};
const styles = document.createElement('style');
styles.innerHTML = 'a[data-base-color], span[data-base] { transition: color 0.25s ease; cursor: pointer; } .FNTslider { border-radius: 4px; position: relative; z-index: 1000; background: #e0e0e0; width: 110px; height: 5px; margin: 3px 5px; border: solid 1px #ccc; float: right; margin-right: 7%; } .FNTslider .before { height: 5px; border: solid 1px transparent; border-right: none; border-radius: 4px 0 0 4px; position: absolute; background: #a0bcda; margin-top: -1px; } .FNTslider .thumb { width: 8px; height: 13px; border-radius: 3px; position: relative; top: -4px; background: #3980d8; cursor: pointer; } #fntSlider:before { content: attr(data) "px"; position: absolute; left: -32px; top: -5px; font-weight: 400; font-size: .9em; } @media (max-width: 768px) { #fntSlider:before { left: calc(100% + 8px); right: auto; } }';
document.head.appendChild(styles);
function applyFontSize(scope = document) {
const selectors = [".post-content p", "#post-preview .post-content p", ".parsedsig", "#profile-signature"];
const stored = localStorage.getItem("FNTsize");
let fontSize = "16";
if (stored) { const parts = stored.split(","); fontSize = parts[1] || "16"; }
selectors.forEach(sel => { scope.querySelectorAll(sel).forEach(el => { el.style.fontSize = fontSize + "px"; }); });
const slider = scope.querySelector("#fntSlider");
if (slider) slider.setAttribute("data", fontSize);
}
function ChangeAll(scope = document) {
[].concat(CONFIG.replacements.profileElements, CONFIG.replacements.postButtons, CONFIG.replacements.miniProfile).forEach(([selector, from, to]) => {
scope.querySelectorAll(selector + ':not([data-replaced])').forEach(el => {
if (el.closest('.quote-box, blockquote, cite')) return;
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false);
let node;
while (node = walker.nextNode()) {
if (node.textContent.includes(from)) node.textContent = node.textContent.replaceAll(from, to);
}
el.dataset.replaced = 'true';
});
});
}
function fixMixedContent(scope) {
if (location.protocol !== 'https:') return;
const root = scope || document;
root.querySelectorAll('img[src^="http://"], source[src^="http://"], iframe[src^="http://"], video source[src^="http://"], audio source[src^="http://"]').forEach(el => { el.src = el.src.replace(/^http:/, 'https:'); });
root.querySelectorAll('[style*="background-image" i]').forEach(el => { el.style.cssText = el.style.cssText.replace(/url\(["']?http:\/\//gi, match => match.replace('http://', 'https://')); });
}
function fixAllMixedContent() {
if (location.protocol !== 'https:') return;
fixMixedContent(document);
document.querySelectorAll('[src^="http://"], [href^="http://"]').forEach(el => {
const attr = el.getAttribute('src') ? 'src' : 'href';
el.setAttribute(attr, el.getAttribute(attr).replace(/^http:\/\//, 'https://'));
});
}
function recolorPostNicks(users, scope = document) {
const userMap = {};
users.forEach(u => { if (u.username) userMap[u.username.trim().toLowerCase()] = parseInt(u.group_id); });
function colorNick(el, username) {
const group_id = userMap[username.toLowerCase()] || 4;
const colors = CONFIG.groupColors[group_id];
if (!colors) return;
el.style.color = colors[0];
el.dataset.baseColor = colors[0];
el.dataset.hoverColor = colors[1] || colors[0];
}
scope.querySelectorAll('.post a[href^="javascript:to("]').forEach(el => {
if (el.closest('.quote-box, .dropdown, #pun-navlinks, .vote-list, .user-menu')) return;
colorNick(el, el.textContent.trim());
});
if (CONFIG.enableIndexNickColoring && document.getElementById('onlinelist')) {
document.querySelectorAll('#onlinelist a[href*="profile.php"]').forEach(el => { colorNick(el, el.textContent.trim()); });
}
}
function recolorMiniProfile(scope = document) {
CONFIG.miniProfileSelectors.forEach(sel => {
scope.querySelectorAll(sel).forEach(el => {
if (el.dataset.mpRecolored) return;
let html = el.innerHTML;
for (const [name, obj] of Object.entries(CONFIG.miniProfileColors)) {
const [base, hover] = obj.color;
if (html.includes(name)) html = html.replace(name, '<span data-base="' + base + '" data-hover="' + hover + '" style="font-weight:bold;color:' + base + ';">' + name + '</span>');
}
el.innerHTML = html;
el.dataset.mpRecolored = 'true';
});
});
}
function recolorAll(scope = document) {
recolorPostNicks(JSON.parse(localStorage.getItem('UsersAdmList')?.split('|')[1] || '[]'), scope);
recolorMiniProfile(scope);
}
function isMessengerPage() { return /messages\.php|inbox|outbox|sendmsg|privmsg/i.test(location.href); }
function fullUpdate(scope = document) {
fixAllMixedContent();
if (isMessengerPage()) { ChangeAll(scope); applyFontSize(scope); return; }
ChangeAll(scope);
recolorAll(scope);
applyFontSize(scope);
}
function fetchUsersAndRecolor(force = false, scope = document) {
const key = 'UsersAdmList';
const now = Math.floor(Date.now() / 1000);
const cached = localStorage.getItem(key);
if (cached && !force) {
try { const [tsStr, usersStr] = cached.split('|'); if ((now - parseInt(tsStr)) < 24 * 3600) { recolorAll(scope); return; } } catch (e) { console.warn(e); }
}
fetch('/api.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ method: 'users.get', limit: '500', fields: 'user_id,username,group_id' }) })
.then(r => r.json())
.then(data => { if (data?.response?.users) { localStorage.setItem(key, now + '|' + JSON.stringify(data.response.users)); recolorAll(scope); } })
.catch(console.error);
}
document.body.addEventListener('mouseover', e => {
const el = e.target.closest('span[data-base], a[data-base-color]');
if (el) el.style.color = el.dataset.hoverColor || el.dataset.hover || el.style.color;
});
document.body.addEventListener('mouseout', e => {
const el = e.target.closest('span[data-base], a[data-base-color]');
if (el) el.style.color = el.dataset.baseColor || el.dataset.base || el.style.color;
});
function initFontSizeSlider() {
if (!document.querySelector(".post")) return;
if (document.getElementById("fntSlider")) return;
const header = document.querySelector(".post:first-of-type h3 > span");
if (!header) return;
const sliderHTML = '<div id="fntSlider" class="FNTslider"><div class="before"></div><div class="thumb"></div></div>';
if (header.querySelector("strong")) { header.querySelector("strong").insertAdjacentHTML('afterend', sliderHTML); } else { header.insertAdjacentHTML('beforeend', sliderHTML); }
const slider = document.getElementById("fntSlider");
const thumb = slider.querySelector(".thumb");
const before = slider.querySelector(".before");
const sliderWidth = slider.offsetWidth;
const paddingLeft = parseInt(getComputedStyle(slider).paddingLeft) || 0;
thumb.title = "Размер шрифта";
let stored = localStorage.getItem("FNTsize");
let fallbackSize = "16";
if (stored) {
const [pos, size, fallback] = stored.split(",");
thumb.style.left = pos + "px";
before.style.width = pos + "px";
fallbackSize = fallback || size;
} else {
const firstP = document.querySelector(".post-content p");
if (firstP) { const computed = parseFloat(getComputedStyle(firstP).fontSize); fallbackSize = Math.round(computed); }
const pos = Math.max(0, (parseInt(fallbackSize) - 6) * 5);
thumb.style.left = pos + "px";
before.style.width = pos + "px";
localStorage.setItem("FNTsize", pos + "," + fallbackSize + "," + fallbackSize);
}
window.__originalFontSize = fallbackSize;
applyFontSize();
function getOffset(el) { const rect = el.getBoundingClientRect(); return { left: rect.left + window.pageXOffset }; }
function startDrag(e) {
e.preventDefault();
const pageX = e.type === "mousedown" ? e.pageX : e.touches?.[0]?.pageX;
if (pageX === undefined) return;
const thumbOffset = getOffset(thumb).left;
const sliderOffset = getOffset(slider).left;
const dragOffset = pageX - thumbOffset;
const maxPos = sliderWidth - thumb.offsetWidth;
function moveHandler(ev) {
ev.preventDefault();
const currentX = ev.type === "mousemove" ? ev.pageX : ev.touches?.[0]?.pageX;
if (currentX === undefined) return;
let newPos = currentX - dragOffset - sliderOffset - paddingLeft;
newPos = Math.max(0, Math.min(newPos, maxPos));
thumb.style.left = newPos + "px";
before.style.width = newPos + "px";
let fontSize = Math.round(newPos / 5) + 6;
if (fontSize > 30) fontSize = 30;
localStorage.setItem("FNTsize", newPos + "," + fontSize + "," + window.__originalFontSize);
applyFontSize();
}
function stopHandler() {
document.removeEventListener("mousemove", moveHandler);
document.removeEventListener("mouseup", stopHandler);
document.removeEventListener("touchmove", moveHandler, { passive: false });
document.removeEventListener("touchend", stopHandler);
}
document.addEventListener("mousemove", moveHandler);
document.addEventListener("mouseup", stopHandler);
document.addEventListener("touchmove", moveHandler, { passive: false });
document.addEventListener("touchend", stopHandler);
}
thumb.addEventListener("mousedown", startDrag);
thumb.addEventListener("touchstart", startDrag, { passive: false });
thumb.ondragstart = () => false;
slider.addEventListener("dblclick", () => {
const fallback = window.__originalFontSize || "16";
localStorage.removeItem("FNTsize");
const resetPos = Math.max(0, (parseInt(fallback) - 6) * 5);
thumb.style.left = resetPos + "px";
before.style.width = resetPos + "px";
applyFontSize();
});
}
let scheduled = false;
function scheduleUpdate() {
if (scheduled) return;
scheduled = true;
observer.disconnect();
const updateFunc = () => {
fullUpdate();
scheduled = false;
if (isRelevantPage()) observer.observe(document.body, { childList: true, subtree: true });
};
if (CONFIG.observerDelay === 0) { requestAnimationFrame(updateFunc); } else { setTimeout(updateFunc, CONFIG.observerDelay); }
}
function isRelevantPage() {
if (isMessengerPage()) return false;
return document.querySelector(".post") || document.getElementById("onlinelist");
}
let observer = null;
if (isRelevantPage()) { observer = new MutationObserver(scheduleUpdate); observer.observe(document.body, { childList: true, subtree: true }); }
const topicEvents = ['pun_post', 'pun_edit', 'pun_preview'];
const messengerEvents = ['messenger:post', 'messenger:messages_ready', 'messenger:messages_load'];
topicEvents.forEach(eventName => {
document.addEventListener(eventName, function(e) {
let scope = document.body;
if (e.detail?.post) { scope = e.detail.post; }
else if (e.target && e.target.nodeType === Node.ELEMENT_NODE) { scope = e.target; }
else if (typeof e.pid === 'string' || typeof e.pid === 'number') { const postEl = document.getElementById('p' + e.pid); if (postEl) scope = postEl; }
fullUpdate(scope);
});
});
messengerEvents.forEach(eventName => {
document.addEventListener(eventName, function(e) {
let scope = document.body;
if (e.target && e.target.nodeType === Node.ELEMENT_NODE) scope = e.target;
fullUpdate(scope);
});
});
initFontSizeSlider();
fetchUsersAndRecolor();
applyFontSize();
});
</script>