Voz KIA User Highlighter

Hiện các thành viên đã bị ban trên voz

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Voz KIA User Highlighter
// @description  Hiện các thành viên đã bị ban trên voz
// @match        https://voz.vn/*
// @author       itisme
// @version      1.0
// @icon         https://voz.vn/styles/next/xenforo/voz-logo-192.png?v=1
// @grant        none
// @run-at       document-start
// @license      GPL-3.0
// @namespace    https://greasyfork.org/users/1249647
// ==/UserScript==

document.addEventListener('DOMContentLoaded', () => {
    'use strict';

    const observer = new IntersectionObserver(handleIntersection);
    const mutationObserver = new MutationObserver(handleMutations);
    const cache = new Map();

    function applyKiaStyle(el) {
        el.style.color = 'red';
        el.style.textDecoration = "line-through";
    }

    function getUsernameById(id) {
        const selectors = [
            `.message-userDetails a.username[data-user-id='${id}']`,
            `h4.attribution a.username[data-user-id='${id}']`,
            `.comment-contentWrapper a.username.comment-user[data-user-id='${id}']`,
            `.memberTooltip-nameWrapper a.username[data-user-id='${id}']`
        ];
        for (const selector of selectors) {
            const element = document.querySelector(selector);
            if (element) return element.innerText;
        }
        return '';
    }

    function findUser(id, el) {
        if (cache.has(id)) {
            if (cache.get(id)) applyKiaStyle(el);
            return;
        }

        const token = document.getElementsByName("_xfToken")[0]?.value;
        if (!token) {
            console.error('Token not found');
            return;
        }

        const username = getUsernameById(id);
        if (!username) return;

        const queryUrl = `https://voz.vn/index.php?members/find&q=${encodeURIComponent(username)}&_xfRequestUri=${document.location.pathname}&_xfWithData=1&_xfToken=${token}&_xfResponseType=json`;

        fetch(queryUrl)
            .then(response => response.json())
            .then(data => {
                const isKIA = !data.results.some(r => r.id === username);
                cache.set(id, isKIA);
                if (isKIA) applyKiaStyle(el);
            })
            .catch(console.error);
    }

    function handleIntersection(entries) {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const id = entry.target.getAttribute("data-user-id");
                if (id) findUser(id, entry.target);
            }
        });
    }

    function handleMutations(mutationsList) {
        mutationsList.forEach(mutation => {
            if (mutation.type === 'childList') {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        const newUsernames = node.querySelectorAll(
                            '.message-userDetails a.username, h4.attribution a.username, .comment-contentWrapper a.username.comment-user, .memberTooltip-nameWrapper a.username'
                        );
                        newUsernames.forEach(el => observer.observe(el));
                    }
                });
            }
        });
    }

    function observeLoadMoreButton() {
        const loadMoreButton = document.querySelector('.message-responseRow.u-jsOnly.js-commentLoader a');
        if (loadMoreButton) {
            loadMoreButton.addEventListener('click', () => {
                mutationObserver.observe(document.body, { childList: true, subtree: true });
            });
        }
    }

    function observeAllUsernames() {
        const selectors = [
            '.message-userDetails a.username',
            'h4.attribution a.username',
            '.comment-contentWrapper a.username.comment-user',
            '.memberTooltip-nameWrapper a.username'
        ];
        const els = document.querySelectorAll(selectors.join(','));
        els.forEach(el => observer.observe(el));
    }

    observeAllUsernames();
    mutationObserver.observe(document.body, { childList: true, subtree: true });
    observeLoadMoreButton();

    // Optional: Listen for AJAX complete events, if applicable
    document.addEventListener('ajaxComplete', () => {
        const newUsernames = document.querySelectorAll(
            '.message-userDetails a.username, h4.attribution a.username, .comment-contentWrapper a.username.comment-user, .memberTooltip-nameWrapper a.username'
        );
        newUsernames.forEach(el => observer.observe(el));
    });
});