// ==UserScript==
// @name Panel Control XFilter 2.4.54 (c) tapeavion
// @namespace http://tampermonkey.net/
// @version 2.4.54
// @description Hide posts by keywords with the dashboard and hide posts from verified accounts
// @author gullampis810
// @match https://blank.org/*
// @match https://x.com/*
// @match https://x.com/i/grok*
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @license MIT
// @icon https://www.pinclipart.com/picdir/big/450-4507608_twitter-circle-clipart.png
// ==/UserScript==
(function () {
"use strict";
// ===== Настройки и инициализация ===== //
const STORAGE_KEY = "hiddenKeywords";
const FAVORITE_USERS_KEY = "favoriteUsers";
let hiddenKeywords = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
let favoriteUsers = JSON.parse(localStorage.getItem(FAVORITE_USERS_KEY)) || [];
let unblockedKeywords = JSON.parse(localStorage.getItem("unblockedKeywords")) || [];
let hideVerifiedAccounts = false;
let hideNonVerifiedAccounts = JSON.parse(localStorage.getItem("hideNonVerifiedAccounts")) || false;
let isShowingFavorites = false;
const languageFilters = {
english: /[a-zA-Z]/,
russian: /[А-Яа-яЁё]/,
japanese: /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}]/u,
ukrainian: /[А-Яа-яІіЄєЇїҐґ]/,
belarusian: /[А-Яа-яЎўЁёІі]/,
tatar: /[А-Яа-яӘәӨөҮүҖҗ]/,
mongolian: /[\p{Script=Mongolian}]/u,
chinese: /[\p{Script=Han}]/u,
german: /[a-zA-ZßÄäÖöÜü]/,
polish: /[a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]/,
french: /[a-zA-Zàâçéèêëîïôûùüÿ]/,
swedish: /[a-zA-ZåäöÅÄÖ]/,
estonian: /[a-zA-ZäõöüÄÕÖÜ]/,
danish: /[a-zA-Z帿ŨÆ]/,
turkish: /[a-zA-ZıİçÇğĞöÖşŞüÜ]/,
portuguese: /[a-zA-Zàáâãçéêíóôõúü]/,
persian: /[\u0600-\u06FF\u0750-\u077F]/,
arabic: /[\u0600-\u06FF]/,
hebrew: /[\u0590-\u05FF]/,
thai: /[\u0E00-\u0E7F]/
};
let activeLanguageFilters = {};
// ===== Сохранение в localStorage ===== //
function saveKeywords() { localStorage.setItem(STORAGE_KEY, JSON.stringify(hiddenKeywords)); }
function saveFavoriteUsers() { localStorage.setItem(FAVORITE_USERS_KEY, JSON.stringify(favoriteUsers)); }
function saveUnblockedKeywords() { localStorage.setItem("unblockedKeywords", JSON.stringify(unblockedKeywords)); }
// ===== Функции фильтрации языка ===== //
function updateLanguageFilter(language) {
if (activeLanguageFilters[language]) delete activeLanguageFilters[language];
else activeLanguageFilters[language] = languageFilters[language];
hidePosts();
}
function isTextInLanguage(text) {
for (const [language, regex] of Object.entries(activeLanguageFilters)) {
if (regex.test(text)) return true;
}
return false;
}
// ===== Функция скрытия постов с анимацией ===== //
function hidePosts() {
document.querySelectorAll("article").forEach((article) => {
const textContent = article.innerText.toLowerCase();
const isVerifiedAccount = article.querySelector('[data-testid="icon-verified"]');
const usernameElement = article.querySelector('a[href*="/"]');
const username = usernameElement ? usernameElement.getAttribute("href").slice(1).toLowerCase() : "";
const isFavoriteUser = favoriteUsers.includes(username);
const matchesKeyword = hiddenKeywords.some((keyword) => {
try { return new RegExp(keyword, "i").test(textContent); }
catch (e) { return textContent.includes(keyword.toLowerCase()); }
});
const shouldHideVerified = hideVerifiedAccounts && isVerifiedAccount;
const shouldHideNonVerified = hideNonVerifiedAccounts && !isVerifiedAccount;
const shouldHideByLanguage = isTextInLanguage(textContent);
const shouldHideByKeyword = matchesKeyword;
if (isFavoriteUser) {
// Показываем пост, если это избранный пользователь
article.style.height = "";
article.style.opacity = "1";
article.style.display = "";
article.style.margin = ""; // Сбрасываем отступы
article.style.padding = ""; // Сбрасываем padding
return;
}
if (shouldHideVerified || shouldHideNonVerified || shouldHideByLanguage || shouldHideByKeyword) {
if (article.style.display !== "none") {
// Запускаем анимацию скрытия
article.style.transition = "height 0.5s ease, opacity 0.5s ease";
article.style.height = article.scrollHeight + "px";
article.style.opacity = "1";
setTimeout(() => {
article.style.height = "0";
article.style.opacity = "0";
article.style.margin = "0"; // Убираем отступы
article.style.padding = "0"; // Убираем padding
}, 10);
article.addEventListener("transitionend", () => {
if (article.style.height === "0px") {
article.style.display = "none"; // Полностью скрываем элемент
article.style.height = "0"; // Убедимся, что высота 0
article.style.margin = "0"; // Убираем отступы
article.style.padding = "0"; // Убираем padding
}
}, { once: true });
}
} else {
if (article.style.display === "none") {
// Показываем пост с анимацией
article.style.display = "";
article.style.transition = "height 0.5s ease, opacity 0.5s ease";
article.style.height = "0";
article.style.opacity = "0";
setTimeout(() => {
article.style.height = article.scrollHeight + "px";
article.style.opacity = "1";
}, 10);
article.addEventListener("transitionend", () => {
if (article.style.height !== "0px") {
article.style.height = "";
}
}, { once: true });
}
}
});
}
// Вызываем эту функцию после скрытия постов
function adjustParentContainers() {
document.querySelectorAll("article").forEach((article) => {
if (article.style.display === "none") {
let parent = article.parentElement;
while (parent && parent !== document.body) {
// Если у родителя есть фиксированная высота, сбрасываем её
if (parent.style.height && parent.style.height !== "auto") {
parent.style.height = "auto";
}
// Убираем лишние отступы у родителя
parent.style.margin = "0";
parent.style.padding = "0";
parent = parent.parentElement;
}
}
});
}
// ===== Создание основной панели ===== //
const panel = document.createElement("div");
panel.style.position = "fixed";
panel.style.bottom = "62px";
panel.style.right = "180px";
panel.style.width = "335px";
panel.style.height = "525px";
panel.style.padding = "8px";
panel.style.fontFamily = "Arial, sans-serif";
panel.style.backgroundColor = "#34506c";
panel.style.color = "#fff";
panel.style.borderRadius = "8px";
panel.style.boxShadow = "0 0 10px rgba(0,0,0,0.5)";
panel.style.zIndex = "9999";
panel.style.overflow = "auto";
panel.style.transition = "height 0.3s ease";
panel.innerHTML = `
<h3 style="margin: 0; font-size: 16px;">Hiding Control</h3>
<h4 class="version-text">v2.4.54</h4>
<input id="keywordInput" type="text" placeholder="Enter the word or @username" style="width: calc(100% - 95px); height: 30px; padding: 5px; margin: 10px 0; border-radius: 5px; border: none;">
<div id="notification" style="display: none; color: #ffcc00; font-size: 14px; margin-bottom: 5px;"></div>
<div style="display: flex; flex-wrap: wrap; gap: 5px; position: relative;">
<button id="addKeyword" style="flex: 1; min-width: 70px; max-width: 70px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px;">Add it</button>
<button id="exportKeywords" style="flex: 1; min-width: 60px; max-width: 70px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px;">Export</button>
<button id="importKeywords" style="flex: 1; min-width: 60px; max-width: 70px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px;">Import</button>
<button id="toggleBlockKeywords" style="flex: 1; min-width: 80px; max-width: 90px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Unblock All</button>
<button id="clearKeywords" style="flex: 1; min-width: 60px; max-width: 80px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px;">Clear all</button>
<button id="toggleVerifiedPosts" style="width: 242px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Hide verified accounts: Click to Disable</button>
<button id="toggleNonVerifiedPosts" style="width: 242px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Hide non-verified accounts: Turn ON</button>
<button id="openLanguagePopup" style="width: 80px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Language Filtering</button>
<button id="toggleFavoriteUsers" style="width: 80px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Favorite Users</button>
</div>
<div id="listLabel" style="margin-top: 10px; font-size: 14px; color: #fff;">List of Keywords</div>
<ul id="keywordList" style="list-style: position: relative; inside; padding: 0; margin-top: 5px; font-size: 14px; color: #fff; max-height: 135px; overflow-y: auto; border: 1px solid #ccc; border-radius: 5px; background-color: #15202b; box-shadow: 0 2px 5px rgba(0,0,0,0.3);"></ul>
`;
document.body.appendChild(panel);
// ===== Панель со счетчиками ===== //
const counterPanel = document.createElement("div");
counterPanel.style.marginTop = "10px";
counterPanel.style.padding = "8px";
counterPanel.style.border = "2px solid #34506c";
counterPanel.style.borderRadius = "5px";
counterPanel.style.backgroundColor = "transparent";
counterPanel.innerHTML = `
<div style="font-size: 14px; color: #fff;">Favorite Users: <span id="favoriteUsersCount">${favoriteUsers.length}</span></div>
<div style="font-size: 14px; color: #fff; margin-top: 5px;">Blocked Keywords: <span id="blockedKeywordsCount">${hiddenKeywords.length}</span></div>
`;
panel.appendChild(counterPanel);
const lengthFilterInput = document.createElement("input");
lengthFilterInput.type = "number";
lengthFilterInput.placeholder = "Min length";
lengthFilterInput.style.width = "80px";
lengthFilterInput.style.marginTop = "10px";
panel.appendChild(lengthFilterInput);
lengthFilterInput.addEventListener("change", () => debouncedHidePosts());
const keywordInput = panel.querySelector("#keywordInput");
keywordInput.addEventListener("mousedown", (event) => event.stopPropagation());
let isDragging = false;
let offsetX = 0;
let offsetY = 0;
panel.addEventListener("mousedown", (event) => {
isDragging = true;
offsetX = event.clientX - panel.offsetLeft;
offsetY = event.clientY - panel.offsetTop;
panel.style.cursor = "grabbing";
});
document.addEventListener("mousemove", (event) => {
if (isDragging) {
panel.style.left = event.clientX - offsetX + "px";
panel.style.top = event.clientY - offsetY + "px";
}
});
document.addEventListener("mouseup", () => {
isDragging = false;
panel.style.cursor = "grab";
});
// ===== Попап для языков ===== //
const languagePopup = document.createElement("div");
languagePopup.style.display = "none";
languagePopup.style.position = "fixed";
languagePopup.style.top = "460px";
languagePopup.style.right = "65px";
languagePopup.style.transform = "translate(-52%, 7%)";
languagePopup.style.backgroundColor = "#34506c";
languagePopup.style.padding = "20px";
languagePopup.style.borderRadius = "8px";
languagePopup.style.zIndex = "10000";
languagePopup.style.width = "8%";
languagePopup.style.boxShadow = "0 0 10px rgba(0,0,0,0.5)";
languagePopup.style.fontFamily = "Arial, sans-serif";
for (const language in languageFilters) {
const wrapper = document.createElement("div");
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.id = `lang-${language}`;
checkbox.name = language;
const label = document.createElement("label");
label.htmlFor = `lang-${language}`;
label.textContent = language.charAt(0).toUpperCase() + language.slice(1);
wrapper.appendChild(checkbox);
wrapper.appendChild(label);
languagePopup.appendChild(wrapper);
}
const closeButton = document.createElement("button");
closeButton.textContent = "X";
closeButton.style.position = "relative";
closeButton.style.width = "40px";
closeButton.style.height = "40px";
closeButton.style.borderRadius = "50%";
closeButton.style.backgroundColor = "#203142";
closeButton.style.color = "#fff";
closeButton.style.border = "none";
closeButton.style.display = "flex";
closeButton.style.alignItems = "center";
closeButton.style.justifyContent = "center";
closeButton.style.cursor = "pointer";
closeButton.style.marginTop = "10px";
closeButton.style.left = "82%";
closeButton.style.top = "56px";
closeButton.addEventListener("click", () => languagePopup.style.display = "none");
languagePopup.appendChild(closeButton);
document.body.appendChild(languagePopup);
const warningText = document.createElement("div");
warningText.textContent = "⚠️it may stops working";
warningText.style.color = "#ffcc00";
warningText.style.fontSize = "14px";
warningText.style.marginBottom = "10px";
warningText.style.textAlign = "end";
warningText.style.right = "38px";
warningText.style.position = "relative";
warningText.style.top = "20px";
languagePopup.appendChild(warningText);
for (const language in languageFilters) {
document.getElementById(`lang-${language}`).addEventListener("change", () => updateLanguageFilter(language));
}
// ===== Стили с добавлением анимации ===== //
const style = document.createElement("style");
style.textContent = `
button { transition: box-shadow 0.3s, transform 0.3s; }
button:hover { box-shadow: 0 0 10px rgba(255, 255, 255, 0.7); }
button:active { transform: scale(0.95); box-shadow: 0 0 5px rgba(255, 255, 255, 0.7); }
#keywordList::-webkit-scrollbar { width: 25px; }
#keywordList::-webkit-scrollbar-thumb { background-color: #C1A5EF; border-radius: 8px; border: 3px solid #4F3E6A; height: 80px; }
#keywordList::-webkit-scrollbar-thumb:hover { background-color: #C6AEFF; }
#keywordList::-webkit-scrollbar-thumb:active { background-color: #B097C9; }
#keywordList::-webkit-scrollbar-track { background: #455565; border-radius: 0px 0px 8px 0px; }
.version-text { left: 290px; position: relative; bottom: 18px; color: #15202b; margin: 0; font-size: 14px; }
#keywordInput { cursor: text; }
article {
overflow: hidden;
margin: 0; /* Убираем базовые отступы */
padding: 0; /* Убираем базовый padding */
}
article[style*="display: none"] {
margin: 0 !important; /* Принудительно убираем отступы для скрытых постов */
padding: 0 !important;
height: 0 !important;
}
article[style*="display: none"] + * {
margin-top: 0 !important;
padding-top: 0 !important;
}
`;
document.head.appendChild(style);
// ===== Переключатель FilterX ===== //
let isSwitchOn = localStorage.getItem("isSwitchOn") === "true";
const toggleButton = document.createElement("div");
toggleButton.style.position = "fixed";
toggleButton.style.top = "94%";
toggleButton.style.right = "90px";
toggleButton.style.width = "192px";
toggleButton.style.display = "flex";
toggleButton.style.alignItems = "center";
toggleButton.style.gap = "10px";
toggleButton.style.zIndex = "1";
toggleButton.style.background = "#15202b";
toggleButton.style.border = "4px solid #6c7e8e";
toggleButton.style.borderRadius = "18px";
toggleButton.style.display = window.location.href.startsWith("https://x.com/i/grok") ? "none" : "flex";
const toggleLabel = document.createElement("label");
toggleLabel.style.display = "inline-block";
toggleLabel.style.width = "50px";
toggleLabel.style.height = "25px";
toggleLabel.style.borderRadius = "25px";
toggleLabel.style.backgroundColor = isSwitchOn ? "#425364" : "#0d1319";
toggleLabel.style.position = "relative";
toggleLabel.style.cursor = "pointer";
toggleLabel.style.transition = "background-color 0.3s";
const toggleSwitch = document.createElement("div");
toggleSwitch.style.position = "absolute";
toggleSwitch.style.width = "21px";
toggleSwitch.style.height = "21px";
toggleSwitch.style.borderRadius = "50%";
toggleSwitch.style.backgroundColor = "#6c7e8e";
toggleSwitch.style.top = "2px";
toggleSwitch.style.left = isSwitchOn ? "calc(100% - 23px)" : "2px";
toggleSwitch.style.transition = "left 0.3s ease";
toggleSwitch.style.boxShadow = "rgb(21, 32, 43) -1px 1px 4px 1px";
function toggleSwitchState() {
isSwitchOn = !isSwitchOn;
localStorage.setItem("isSwitchOn", isSwitchOn.toString());
toggleSwitch.style.left = isSwitchOn ? "calc(100% - 23px)" : "2px";
toggleLabel.style.backgroundColor = isSwitchOn ? "#425364" : "#0d1319";
}
toggleButton.addEventListener("click", toggleSwitchState);
toggleLabel.appendChild(toggleSwitch);
toggleButton.appendChild(toggleLabel);
const toggleText = document.createElement("span");
toggleText.textContent = "Panel FilterX";
toggleText.style.color = "#6c7e8e";
toggleText.style.fontFamily = "Arial, sans-serif";
toggleText.style.fontSize = "16px";
toggleText.style.marginLeft = "10px";
toggleText.style.fontWeight = "bold";
toggleButton.appendChild(toggleText);
document.body.appendChild(toggleButton);
let isPanelVisible = localStorage.getItem("panelVisible") === "true";
function togglePanel() {
if (isPanelVisible) {
panel.style.height = "0px";
setTimeout(() => panel.style.display = "none", 300);
} else {
panel.style.display = "block";
setTimeout(() => panel.style.height = "525px", 10);
}
isPanelVisible = !isPanelVisible;
localStorage.setItem("panelVisible", isPanelVisible.toString());
}
toggleButton.addEventListener("click", togglePanel);
if (isPanelVisible) {
panel.style.height = "525px";
panel.style.display = "block";
} else {
panel.style.height = "0px";
panel.style.display = "none";
}
// ===== Элементы управления ===== //
const addKeywordBtn = panel.querySelector("#addKeyword");
const clearKeywordsBtn = panel.querySelector("#clearKeywords");
const exportKeywordsBtn = panel.querySelector("#exportKeywords");
const importKeywordsBtn = panel.querySelector("#importKeywords");
const toggleVerifiedBtn = panel.querySelector("#toggleVerifiedPosts");
const toggleNonVerifiedBtn = panel.querySelector("#toggleNonVerifiedPosts");
const toggleBlockBtn = panel.querySelector("#toggleBlockKeywords");
const openLanguagePopupBtn = panel.querySelector("#openLanguagePopup");
const toggleFavoriteUsersBtn = panel.querySelector("#toggleFavoriteUsers");
const keywordList = panel.querySelector("#keywordList");
addKeywordBtn.addEventListener("click", () => {
const inputValue = keywordInput.value.trim();
const notification = panel.querySelector("#notification");
if (inputValue) {
let added = false;
if (isShowingFavorites && inputValue.startsWith("@")) {
const username = inputValue.slice(1).toLowerCase();
if (!favoriteUsers.includes(username)) {
favoriteUsers.push(username);
saveFavoriteUsers();
updateKeywordList();
debouncedHidePosts();
added = true;
} else {
notification.textContent = "This user is already in your favorites!";
notification.style.display = "block";
keywordInput.style.border = "2px solid #ffcc00"; // Подсвечиваем поле
setTimeout(() => {
notification.style.display = "none";
keywordInput.style.border = "none"; // Сбрасываем подсветку
}, 3000);
}
} else if (!isShowingFavorites && !hiddenKeywords.includes(inputValue)) {
hiddenKeywords.push(inputValue);
saveKeywords();
updateKeywordList();
debouncedHidePosts();
added = true;
} else {
notification.textContent = "This keyword is already in the list!";
notification.style.display = "block";
keywordInput.style.border = "2px solid #ffcc00"; // Подсвечиваем поле
setTimeout(() => {
notification.style.display = "none";
keywordInput.style.border = "none"; // Сбрасываем подсветку
}, 3000);
}
if (added) {
keywordInput.value = "";
keywordInput.style.border = "none"; // Сбрасываем подсветку при успешном добавлении
}
}
});
toggleNonVerifiedBtn.textContent = `Hide non-verified accounts: ${hideNonVerifiedAccounts ? "Turn OFF" : "Turn ON"}`;
toggleNonVerifiedBtn.addEventListener("click", () => {
hideNonVerifiedAccounts = !hideNonVerifiedAccounts;
localStorage.setItem("hideNonVerifiedAccounts", JSON.stringify(hideNonVerifiedAccounts));
toggleNonVerifiedBtn.textContent = `Hide non-verified accounts: ${hideNonVerifiedAccounts ? "Turn OFF" : "Turn ON"}`;
hidePosts();
});
clearKeywordsBtn.addEventListener("click", () => {
if (confirm("Are you sure you want to clear the list?")) {
if (isShowingFavorites) {
favoriteUsers = [];
saveFavoriteUsers();
} else {
hiddenKeywords = [];
unblockedKeywords = [];
saveKeywords();
saveUnblockedKeywords();
}
updateKeywordList();
hidePosts();
}
});
exportKeywordsBtn.addEventListener("click", () => {
const data = isShowingFavorites ? favoriteUsers : hiddenKeywords;
const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(data))}`;
const downloadAnchor = document.createElement("a");
downloadAnchor.setAttribute("href", dataStr);
downloadAnchor.setAttribute("download", isShowingFavorites ? "favorite_users.json" : "hidden_keywords.json");
document.body.appendChild(downloadAnchor);
downloadAnchor.click();
document.body.removeChild(downloadAnchor);
});
importKeywordsBtn.addEventListener("click", () => {
const input = document.createElement("input");
input.type = "file";
input.accept = "application/json";
input.addEventListener("change", (event) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = () => {
try {
const importedData = JSON.parse(reader.result);
if (Array.isArray(importedData)) {
if (isShowingFavorites) {
favoriteUsers = [...new Set([...favoriteUsers, ...importedData.map(u => u.startsWith("@") ? u.slice(1).toLowerCase() : u.toLowerCase())])];
saveFavoriteUsers();
} else {
hiddenKeywords = [...new Set([...hiddenKeywords, ...importedData])];
saveKeywords();
}
updateKeywordList();
hidePosts();
} else {
alert("Incorrect file format.");
}
} catch (e) {
alert("Error reading the file.");
}
};
reader.readAsText(file);
});
input.click();
});
toggleBlockBtn.textContent = hiddenKeywords.length > 0 ? "Unblock All" : "Block All";
toggleBlockBtn.addEventListener("click", () => {
if (!isShowingFavorites) {
if (hiddenKeywords.length > 0) {
unblockedKeywords = [...hiddenKeywords];
hiddenKeywords = [];
toggleBlockBtn.textContent = "Block All";
} else {
hiddenKeywords = [...unblockedKeywords];
unblockedKeywords = [];
toggleBlockBtn.textContent = "Unblock All";
}
saveKeywords();
saveUnblockedKeywords();
updateKeywordList();
hidePosts();
}
});
toggleVerifiedBtn.addEventListener("click", () => {
hideVerifiedAccounts = !hideVerifiedAccounts;
toggleVerifiedBtn.textContent = `Hide verified accounts: ${hideVerifiedAccounts ? "Turn OFF" : "Turn ON"}`;
hidePosts();
});
toggleFavoriteUsersBtn.addEventListener("click", () => {
isShowingFavorites = !isShowingFavorites;
toggleFavoriteUsersBtn.textContent = isShowingFavorites ? "Keywords" : "Favorite Users";
keywordInput.placeholder = isShowingFavorites ? "Enter @username" : "Enter the word";
updateKeywordList();
});
openLanguagePopupBtn.addEventListener("click", () => {
const panelRect = panel.getBoundingClientRect();
languagePopup.style.top = `${panelRect.top - 320}px`;
languagePopup.style.left = `${panelRect.right - 10}px`;
languagePopup.style.display = "block";
});
function updateKeywordList() {
const list = keywordList;
const label = panel.querySelector("#listLabel");
list.innerHTML = "";
if (isShowingFavorites) {
label.textContent = "Favorite Users";
favoriteUsers.forEach((user, index) => {
const listItem = document.createElement("li");
listItem.textContent = `@${user}`;
listItem.style.marginBottom = "5px";
const deleteButton = document.createElement("button");
deleteButton.textContent = "❌";
deleteButton.style.marginLeft = "10px";
deleteButton.style.backgroundColor = "#f44336";
deleteButton.style.color = "#fff";
deleteButton.style.border = "none";
deleteButton.style.borderRadius = "3px";
deleteButton.style.cursor = "pointer";
deleteButton.addEventListener("click", () => {
favoriteUsers.splice(index, 1);
saveFavoriteUsers();
updateKeywordList();
hidePosts();
});
listItem.appendChild(deleteButton);
list.appendChild(listItem);
});
if (favoriteUsers.length === 0) list.textContent = "Нет";
} else {
label.textContent = "List of Keywords";
hiddenKeywords.forEach((keyword, index) => {
const listItem = document.createElement("li");
listItem.textContent = keyword;
listItem.style.marginBottom = "5px";
const deleteButton = document.createElement("button");
deleteButton.textContent = "❌";
deleteButton.style.marginLeft = "10px";
deleteButton.style.backgroundColor = "#f44336";
deleteButton.style.color = "#fff";
deleteButton.style.border = "none";
deleteButton.style.borderRadius = "3px";
deleteButton.style.cursor = "pointer";
deleteButton.addEventListener("click", () => {
hiddenKeywords.splice(index, 1);
saveKeywords();
updateKeywordList();
hidePosts();
});
listItem.appendChild(deleteButton);
list.appendChild(listItem);
});
if (hiddenKeywords.length === 0) list.textContent = "Нет";
}
updateCounters();
}
function updateCounters() {
panel.querySelector("#favoriteUsersCount").textContent = favoriteUsers.length;
panel.querySelector("#blockedKeywordsCount").textContent = hiddenKeywords.length;
}
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
const debouncedHidePosts = debounce(hidePosts, 200);
const observer = new MutationObserver(() => debouncedHidePosts());
observer.observe(document.body, { childList: true, subtree: true });
function isPhotoViewerOpen() {
const currentUrl = window.location.href;
const isPhotoOpen = /\/photo\/\d+$/.test(currentUrl);
const photoModal = document.querySelector('div[aria-label="Image"]') || document.querySelector('div[data-testid="imageViewer"]');
return isPhotoOpen || !!photoModal;
}
function isGrokPage() {
return window.location.href.startsWith("https://x.com/i/grok");
}
function updateToggleButtonVisibility() {
toggleButton.style.display = isGrokPage() ? "none" : "flex";
}
function toggleElementsVisibility() {
const isPhotoOpen = isPhotoViewerOpen();
if (isPhotoOpen || isGrokPage()) {
panel.style.display = "none";
toggleButton.style.display = "none";
} else {
if (isPanelVisible) {
panel.style.display = "block";
panel.style.height = "525px";
}
toggleButton.style.display = "flex";
}
}
toggleElementsVisibility();
window.addEventListener("popstate", () => {
updateToggleButtonVisibility();
toggleElementsVisibility();
});
const urlObserver = new MutationObserver(() => {
updateToggleButtonVisibility();
toggleElementsVisibility();
});
urlObserver.observe(document.body, { childList: true, subtree: true });
document.addEventListener("click", (event) => {
if (event.target.closest('div[aria-label="Close"]') || event.target.closest('div[data-testid="imageViewer-close"]')) {
setTimeout(toggleElementsVisibility, 100);
}
});
updateKeywordList();
hidePosts();
})();