<!-- Скрипт. Вкладки в постах вв-кодами. (done by Kolobdur) -->
<script type="text/javascript" src="https://forumstatic.ru/files/001a/ad/c5/36868.js"></script>
<script>
(function () {
var cthemeID = 828;
var cpageID = null;
var cbaseID = "811";
var ckeys = {
"НПС": "npc",
"квест": "quest",
"сюжетный": "main",
"Грейв-Лейк": "grave_lake",
"Шоссе": "il_14_highway",
"туман": "fog",
"полицейский": "police_station",
"Историческое": "historical_society",
"лазарет": "lazaretto",
"школа": "st_mark_school",
"церковь": "church",
"радиорубка": "radio_shack",
"мастерская": "workshop",
"лесопилка": "sawmill",
"сторожка": "graveyard_cabin",
"кладбище": "cemetery",
"DVD-прокат": "redbox_rental",
"Закусочная": "marta_snack_bar",
"Ресторан": "kfc_restaurant",
"Бар": "decrepit_sheep_bar",
"#1": "home1",
"#2": "home2",
"#3": "home3",
"#4": "home4",
"#5": "home5",
"#6": "home6",
"#7": "home7",
"#8": "home8",
"#9": "home9",
"#10": "home10",
"#11": "home11",
"общежитие": "dormitory",
"браунов": "brown_farm",
"уилсонов": "wilson_farm",
"Другое": "another",
"тьма": "dark",
"приезд": "welcome"
};
async function fetchPosts(topicId) {
try {
const apiUrl = `/api.php?method=post.get&topic_id=${topicId}&limit=200&sort_dir=asc&fields=id,user_id,message`;
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error(`Ошибка API: ${response.status}`);
}
const data = await response.json();
if (!data.response || !Array.isArray(data.response)) {
console.error("Ошибка: Данные из API не содержат массив в поле 'response'.");
return [];
}
return data.response;
} catch (error) {
console.error("Ошибка при получении данных:", error);
return [];
}
}
function processEpisode(post) {
const id = post.id;
const userId = post.user_id;
const message = post.message;
// Проверяем, что message существует
if (!message) {
console.warn(`Сообщение с ID ${id} не содержит HTML-контента.`);
return null;
}
const parser = new DOMParser();
const doc = parser.parseFromString(message, "text/html");
const cepElements = doc.querySelectorAll(".cep");
return Array.from(cepElements).map(cep => {
// Извлекаем дату
const dateElement = cep.querySelector(".cdate p a") || cep.querySelector(".cdate p");
if (!dateElement) {
console.warn(`Элемент .cdate не найден в эпизоде с ID ${id}.`);
return null;
}
let dateText = dateElement.textContent.trim();
const href = dateElement.tagName === "A" ? dateElement.getAttribute("href") : null;
const dateParts = dateText.split("-");
const startDate = new Date(dateParts[0].trim().split(".").reverse().join("-"));
// Извлекаем ключевые слова из .ckeys p и .cloc p
const keysElement = cep.querySelector(".ckeys p");
const locElement = cep.querySelector(".cloc p");
let combinedKeysText = "";
if (keysElement) {
combinedKeysText += keysElement.textContent.trim();
}
if (locElement) {
combinedKeysText += (combinedKeysText ? " " : "") + locElement.textContent.trim();
}
// Разделяем ключи по любым непечатным символам и удаляем пустые значения
const keys = combinedKeysText
? combinedKeysText.split(/\s+|,\s*/).map(key => key.trim()).filter(key => key !== "")
: [];
// Маппинг ключей в классы
const keyClasses = keys.map(key => ckeys[key] || "").filter(cls => cls);
// Если ключей нет, добавляем специальный класс
if (keyClasses.length === 0) {
keyClasses.push("nokeys");
}
// Создаём элемент li
const li = document.createElement("li");
li.className = `allcep ${keyClasses.join(" ")}`;
li.dataset.postId = id;
li.dataset.authId = userId;
// Добавляем ссылки на пост и редактирование
const ceditDiv = document.createElement("div");
ceditDiv.className = "cedit";
const asrcLink = document.createElement("a");
asrcLink.href = `/viewtopic.php?pid=${id}#p${id}`;
asrcLink.className = "asrc";
asrcLink.textContent = "пост";
ceditDiv.appendChild(asrcLink);
if (GroupID === 1 || parseInt(UserID) === parseInt(userId)) {
const editsrcLink = document.createElement("a");
editsrcLink.href = `/edit.php?id=${id}`;
editsrcLink.className = "editsrc";
editsrcLink.textContent = "ред";
ceditDiv.appendChild(editsrcLink);
}
li.appendChild(ceditDiv);
// Создаём контейнер для заголовка
const cheadDiv = document.createElement("div");
cheadDiv.className = "chead";
// Добавляем дату как <span class="cdate">
const cdateSpan = document.createElement("span");
cdateSpan.className = "cdate";
if (href) {
cdateSpan.innerHTML = `<a href="${href}">${dateText}</a>`;
} else {
cdateSpan.textContent = dateText;
}
cheadDiv.appendChild(cdateSpan);
// Добавляем локации как <span class="cloc">
const clocElement = cep.querySelector(".cloc p");
if (clocElement) {
const clocSpan = document.createElement("span");
clocSpan.className = "cloc";
clocSpan.innerHTML = clocElement.innerHTML;
cheadDiv.appendChild(clocSpan);
}
// Добавляем в элемент li
li.appendChild(cheadDiv);
// Добавляем имена персонажей как <div class="cnames">
const namesElement = cep.querySelector(".cnames p");
if (namesElement) {
const cnamesDiv = document.createElement("div");
cnamesDiv.className = "cnames";
cnamesDiv.innerHTML = namesElement.innerHTML;
li.appendChild(cnamesDiv);
}
// Добавляем текст как <div class="ctext">
const textElement = cep.querySelector(".ctext p");
if (textElement) {
const ctextDiv = document.createElement("div");
ctextDiv.className = "ctext";
ctextDiv.textContent = textElement.textContent.trim();
li.appendChild(ctextDiv);
}
return { element: li, date: startDate };
}).filter(ep => ep !== null); // Удаляем null значения
}
async function main() {
if (!cthemeID && !cpageID) {
console.error("Ошибка: Не указаны cthemeID или cpageID.");
return;
}
const baseIds = cbaseID.split(",");
const allEpisodes = [];
// Шаг 1: Собираем все эпизоды из базовых тем
for (const baseId of baseIds) {
const posts = await fetchPosts(baseId.trim());
if (!Array.isArray(posts)) {
console.error(`Ошибка: Полученные данные для topic_id=${baseId} не являются массивом.`);
continue;
}
for (const post of posts) {
const processedEpisodes = processEpisode(post);
if (processedEpisodes) {
allEpisodes.push(...processedEpisodes);
}
}
}
// Шаг 2: Сортируем эпизоды по дате
allEpisodes.sort((a, b) => a.date - b.date);
// Шаг 3: Группируем эпизоды по месяцам
const groupedEpisodes = {};
const monthNamesRU = [
"Январь", "Февраль", "Март", "Апрель", "Май", "Июнь",
"Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"
];
const monthNamesEN = [
"january", "february", "march", "april", "may", "june",
"july", "august", "september", "october", "november", "december"
];
for (const episode of allEpisodes) {
const monthIndex = episode.date.getMonth(); // Индекс месяца (0-11)
const year = episode.date.getFullYear(); // Год
const monthKey = `${year}-${monthIndex}`; // Уникальный ключ для года и месяца
if (!groupedEpisodes[monthKey]) {
groupedEpisodes[monthKey] = {
monthNameRU: monthNamesRU[monthIndex], // Русское название месяца
monthNameEN: monthNamesEN[monthIndex], // Английское название месяца
elements: []
};
}
groupedEpisodes[monthKey].elements.push(episode.element);
}
// Шаг 4: Вставляем сгруппированные данные в .allchrono
[cthemeID, cpageID].forEach(targetId => {
if (targetId) {
const targetDiv = document.querySelector(".allchrono");
if (targetDiv) {
targetDiv.innerHTML = ""; // Очищаем содержимое
// Создаём списки для каждого месяца
for (const key in groupedEpisodes) {
const group = groupedEpisodes[key];
const ul = document.createElement("ul");
ul.className = group.monthNameEN; // Используем английское название месяца как класс
// Добавляем заголовок месяца
const h5 = document.createElement("h5");
h5.textContent = group.monthNameRU; // Используем русское название месяца для заголовка
ul.appendChild(h5);
// Добавляем элементы эпизодов
group.elements.forEach(ep => ul.appendChild(ep));
// Добавляем список в контейнер
targetDiv.appendChild(ul);
}
} else {
console.warn("Элемент .allchrono не найден.");
}
}
});
console.log("Хронология успешно обновлена!");
onChronologyUpdated(); // Уведомляем фильтры о завершении обновления
}
main();
})();
</script>
<script>
// Переменные для работы
const tofilter = "allchrono"; // Класс элемента для фильтрации
const filtersList = document.querySelector('.filterslist'); // Контейнер для фильтров
const fgroup1 = {
"январь": "january", "февраль": "february", "март": "march", "апрель": "april",
"май": "may", "июнь": "june", "июль": "july", "август": "august",
"сентябрь": "september", "октябрь": "october", "ноябрь": "november", "декабрь": "december"
};
const fgroup2 = {
"Грейв-Лейк": "grave_lake", "Шоссе IL 14": "il_14_highway", "туман": "fog", "полицейский участок": "police_station",
"Историческое общество": "historical_society", "лазарет": "lazaretto", "школа святого марка": "st_mark_school",
"церковь": "church", "радиорубка": "radio_shack", "мастерская": "workshop", "лесопилка": "sawmill",
"сторожка в кладбище": "graveyard_cabin", "кладбище": "cemetery", "DVD-прокат": "redbox_rental",
"Закусочная": "marta_snack_bar", "Ресторан": "kfc_restaurant", "Бар": "decrepit_sheep_bar",
"дом #1 / 11 elm street": "home1", "дом #2 / 15 elm street": "home2", "дом #3 / 21 elm street": "home3",
"дом #4 / 44 woodbury street": "home4", "дом #5 / 8 maple drive": "home5", "дом #6 / 9 maple drive": "home6",
"дом #7 / 10 maple drive": "home7", "дом #8 / 11 maple drive": "home8", "дом #9 / 3 jefferson street": "home9",
"дом #10 / 14 jefferson street": "home10", "дом #11 / 31 van buren street": "home11", "общежитие / 17 maple drive": "dormitory",
"ферма браунов": "brown_farm", "ферма уилсонов": "wilson_farm", "другое": "another"
};
const fgroup3 = { "нпс": "npc", "квест": "quest", "сюжетный": "main" };
const fgroup4 = { "тьма": "dark", "приезд": "welcome" };
let isChronologyUpdated = false; // Флаг для отслеживания обновления хронологии
// Функция создания группы фильтров
function createFilterGroup(groupName, groupData, initialHide = false) {
const ul = document.createElement('ul');
ul.classList.add(groupName);
for (const [label, className] of Object.entries(groupData)) {
const li = document.createElement('li');
li.textContent = label;
li.classList.add(className);
if (initialHide) {
li.classList.add('ihide');
}
li.addEventListener('click', () => toggleFilter(li));
ul.appendChild(li);
}
return ul;
}
// Добавление групп фильтров
function initializeFilters() {
const allFGroups = document.createElement('div');
allFGroups.classList.add('allfgroups');
allFGroups.appendChild(createFilterGroup('fgroup1', fgroup1));
allFGroups.appendChild(createFilterGroup('fgroup2', fgroup2));
allFGroups.appendChild(createFilterGroup('fgroup3', fgroup3));
allFGroups.appendChild(createFilterGroup('fgroup4', fgroup4, true));
// Создание кнопки сброса
const resetButton = document.createElement('div');
resetButton.classList.add('sbros');
resetButton.innerHTML = '<a href="#" onclick="resetFilters(); return false;">Сбросить фильтры</a>';
// Создание поля поиска
const finder = document.createElement('div');
finder.classList.add('finder');
const textarea = document.createElement('textarea');
textarea.placeholder = 'Поиск по слову';
textarea.addEventListener('input', () => filterBySearch(textarea.value));
finder.appendChild(textarea);
// Добавление элементов в .filterslist
filtersList.appendChild(resetButton);
filtersList.appendChild(allFGroups);
filtersList.appendChild(finder);
}
// Функция переключения состояния фильтра
function toggleFilter(filterElement) {
if (filterElement.classList.contains('ishow')) {
filterElement.classList.remove('ishow');
filterElement.classList.add('ihide');
} else if (filterElement.classList.contains('ihide')) {
filterElement.classList.remove('ihide');
} else {
filterElement.classList.add('ishow');
}
applyFilters();
}
// Функция применения фильтров
function applyFilters() {
const activeFilters = {};
const groups = ['fgroup1', 'fgroup2', 'fgroup3', 'fgroup4'];
groups.forEach(group => {
activeFilters[group] = {
show: [],
hide: []
};
document.querySelectorAll(`.${group} li`).forEach(item => {
if (item.classList.contains('ishow')) {
activeFilters[group].show.push(item.classList[0]);
} else if (item.classList.contains('ihide')) {
activeFilters[group].hide.push(item.classList[0]);
}
});
});
// Применение фильтров к ul (fgroup1)
document.querySelectorAll(`.${tofilter} > ul`).forEach(ul => {
const monthClass = Array.from(ul.classList).find(cls => Object.values(fgroup1).includes(cls));
if (monthClass) {
if (activeFilters.fgroup1.hide.includes(monthClass)) {
ul.style.display = 'none';
} else if (activeFilters.fgroup1.show.length > 0) {
if (activeFilters.fgroup1.show.includes(monthClass)) {
ul.style.display = 'block';
} else {
ul.style.display = 'none';
}
} else {
ul.style.display = '';
}
}
});
// Применение фильтров к li
document.querySelectorAll(`.${tofilter} > ul`).forEach(ul => {
if (ul.style.display === 'none') return;
ul.querySelectorAll('li').forEach(li => {
let show = true;
for (const group of ['fgroup2', 'fgroup3', 'fgroup4']) {
const classes = Array.from(li.classList);
if (activeFilters[group].hide.some(cls => classes.includes(cls))) {
show = false;
}
if (activeFilters[group].show.length > 0 && !activeFilters[group].show.some(cls => classes.includes(cls))) {
show = false;
}
}
li.style.display = show ? '' : 'none';
});
if (ul.style.display !== 'none' && Array.from(ul.querySelectorAll('li')).every(li => li.style.display === 'none')) {
ul.style.display = 'none';
}
});
}
// Функция фильтрации по поиску
function filterBySearch(query) {
if (!query.trim()) {
document.querySelectorAll(`.${tofilter} li`).forEach(li => li.style.display = '');
return;
}
query = query.toLowerCase();
document.querySelectorAll(`.${tofilter} li`).forEach(li => {
const text = li.textContent.toLowerCase();
li.style.display = text.includes(query) ? '' : 'none';
});
document.querySelectorAll(`.${tofilter} > ul`).forEach(ul => {
if (Array.from(ul.querySelectorAll('li')).every(li => li.style.display === 'none')) {
ul.style.display = 'none';
} else {
ul.style.display = '';
}
});
}
// Функция сброса фильтров
window.resetFilters = function () {
document.querySelectorAll('.allfgroups li').forEach(li => {
if (li.closest('.fgroup4')) {
if (!li.classList.contains('ihide')) {
li.classList.remove('ishow');
li.classList.add('ihide');
}
} else {
li.classList.remove('ishow', 'ihide');
}
});
document.querySelectorAll(`.${tofilter} ul, .${tofilter} li`).forEach(el => el.style.display = '');
applyFilters();
};
// Применение начальных фильтров из fgroup4 при загрузке страницы
function applyInitialFilters() {
if (!isChronologyUpdated) {
console.warn("Элементы для фильтрации еще не созданы. Ожидаю завершения обновления хронологии...");
return;
}
// Проверяем, существуют ли элементы fgroup4 с классом ihide
const initialFilters = Array.from(document.querySelectorAll('.fgroup4 li.ihide')).map(li => li.classList[0]);
if (initialFilters.length === 0) {
console.warn("Нет активных фильтров в группе fgroup4 с состоянием ihide. Повторная попытка через 100мс...");
setTimeout(applyInitialFilters, 100); // Повторяем попытку через 100мс
return;
}
const targetContainer = document.querySelector(`.${tofilter}`);
if (!targetContainer) {
console.warn("Контейнер для фильтрации (.allchrono) не найден.");
return;
}
const filterableElements = document.querySelectorAll(`.${tofilter} li`);
if (filterableElements.length === 0) {
console.warn("Элементы для фильтрации (.allchrono li) не найдены.");
return;
}
let filteredItems = 0;
filterableElements.forEach(li => {
if (initialFilters.some(cls => li.classList.contains(cls))) {
li.style.display = 'none';
filteredItems++;
}
});
if (filteredItems === 0) {
console.warn("Нет элементов, соответствующих фильтрам fgroup4 с состоянием ihide.");
} else {
console.log(`${filteredItems} элементов скрыто по начальным фильтрам fgroup4.`);
}
const filterableULs = document.querySelectorAll(`.${tofilter} > ul`);
if (filterableULs.length === 0) {
console.warn("Элементы для фильтрации (.allchrono > ul) не найдены.");
return;
}
filterableULs.forEach(ul => {
if (Array.from(ul.querySelectorAll('li')).every(li => li.style.display === 'none')) {
ul.style.display = 'none';
}
});
}
// Функция для отслеживания завершения обновления хронологии
function onChronologyUpdated() {
isChronologyUpdated = true;
console.log("Хронология успешно обновлена!");
applyInitialFilters(); // Применяем фильтры после обновления хронологии
}
// Инициализация фильтров
document.addEventListener("DOMContentLoaded", () => {
initializeFilters();
});
</script>