Facebook Switch to All comments

To switch Facebook to All comments

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Facebook Switch to All comments
// @namespace    https://docs.scriptcat.org/
// @version      0.1.2
// @description  To switch Facebook to All comments
// @author       CY Fung
// @match        https://www.facebook.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=www.facebook.com
// @grant        none
// @run-at       document-start
// @noframes
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // --------------------------------------------------------------------------------------------------------

    const texts = {
        "en": {
            "Most relevant": "Most relevant",
            "Newest": "Newest",
            "All comments": "All comments",
        },
        "es": {  // Spanish
            "Most relevant": "Más relevantes",
            "Newest": "Más recientes",
            "All comments": "Todos los comentarios",
        },
        "fr": {  // French
            "Most relevant": "Plus pertinents",
            "Newest": "Plus récents",
            "All comments": "Tous les commentaires",
        },
        "de": {  // German
            "Most relevant": "Relevanteste",
            "Newest": "Neueste",
            "All comments": "Alle Kommentare",
        },
        "pt": {  // Portuguese (Brazil)
            "Most relevant": "Mais relevantes",
            "Newest": "Mais recentes",
            "All comments": "Todos os comentários",
        },
        "ar": {  // Arabic (right-to-left language)
            "Most relevant": "الأكثر صلة",
            "Newest": "الأحدث",
            "All comments": "جميع التعليقات",
        },
        "hi": {  // Hindi
            "Most relevant": "सबसे प्रासंगिक",
            "Newest": "नवीनतम",
            "All comments": "सभी टिप्पणियाँ",
        },
        "zh-Hans": {  // Chinese (Simplified)
            "Most relevant": "最相关",
            "Newest": "最新",
            "All comments": "所有评论",
        },
        "zh": {  // Chinese (Simplified)
            "Most relevant": "最相关",
            "Newest": "最新",
            "All comments": "所有评论",
        },
        "zh-Hant": {  // Chinese (Traditional)
            "Most relevant": "最相關",
            "Newest": "由新到舊",
            "All comments": "所有留言",
        },
        "zh_TW": {  // Chinese (Traditional)
            "Most relevant": "最相關",
            "Newest": "由新到舊",
            "All comments": "所有留言",
        },
        "zh_HK": {  // Chinese (Traditional)
            "Most relevant": "最相關",
            "Newest": "由新到舊",
            "All comments": "所有留言",
        },
        "ja": {  // Japanese
            "Most relevant": "関連度の高い順",
            "Newest": "新着順",
            "All comments": "すべてのコメント",
        },
        "ko": {  // Korean
            "Most relevant": "관련도순",
            "Newest": "최신순",
            "All comments": "모든 댓글",
        },
        "ru": {  // Russian
            "Most relevant": "Самые релевантные",
            "Newest": "Новые",
            "All comments": "Все комментарии",
        },
        "id": {  // Indonesian
            "Most relevant": "Paling relevan",
            "Newest": "Terbaru",
            "All comments": "Semua komentar",
        },
        "it": {  // Italian
            "Most relevant": "Più rilevanti",
            "Newest": "Più recenti",
            "All comments": "Tutti i commenti",
        },
        "tr": {  // Turkish
            "Most relevant": "En uygun",
            "Newest": "En yeniler",
            "All comments": "Tüm yorumlar",
        },
    }

    const STATE_INITIAL = 0x0100;
    const STATE_FINAL = 0x0300;

    // const SELECTOR_COMMENT_GRAY_BOX = ".xmjcpbm,.xrgxkkn,.xv2q8z8";
    let SELECTOR_COMMENT_GRAY_BOX = "";
    // const SELECTOR_LOADING_AREA = '[style*="--x-animationDelay"]';

    // --------------------------------------------------------------------------------------------------------

    function getElementByXPath(xpath, context = document) {
        return document.evaluate(
            xpath,
            context,
            null,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
        ).singleNodeValue;
    }

    function getElementsByXPath(xpath, context = document) {
        const results = [];
        const query = document.evaluate(
            xpath,
            context,
            null,
            XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
            null
        );

        for (let i = 0; i < query.snapshotLength; i++) {
            results.push(query.snapshotItem(i));
        }

        return results;
    }

    const startMonitor = (c) => {

        const observer = new MutationObserver(c);
        observer.observe(document, { childList: true, subtree: true });

    };

    const getParentWith = (dom, selector) => {
        let p = dom;
        while (p) {
            if (p.querySelector(selector)) return p;
            p = p.parentNode;
        }
        return null;
    };

    const getLangText = () => {
        const lang = document.documentElement.lang;
        const text = texts[lang] || texts["en"];
        return text;
    };

    const setTimeout_ = setTimeout;

    const randInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
    const mFloor = (x, m) => Math.floor(x / m) * m;
    const setTimeoutQ = (e, d) => {
        d = mFloor(d, 10) + mFloor(randInt(2, 8), 2) + mFloor(randInt(24, 48), 2) / 100 + Math.random() * 0.01;
        return setTimeout_(e, d);
    }

    const deferred = () => {
        let resolve;
        let reject;
        const promise = new Promise((res, rej) => {
            resolve = res;
            reject = rej;
        });
        return { promise, resolve, reject };
    };

    // --------------------------------------------------------------------------------------------------------

    const obtainClass = () => {

        const cutClass = (cssText, search) => {
            let idx = cssText.indexOf(search);
            if (idx > 0) {
                let jdx = cssText.lastIndexOf("{", idx);
                if (jdx > 0) {
                    return cssText.substring(0, jdx) || "";
                }
            }
            return "";
        }

        const selfStaticClass = (c) => {
            if (!c) return "";
            const m = c.trim().split(/\s+/);
            const s = m[m.length - 1];
            if (s.includes(":")) return "";
            return s || "";
        }


        const rulesList = [];

        for (const sheet of document.styleSheets) {
            const rules = sheet.cssRules || sheet.rules;
            if (rules.length > 300) {
                rulesList.push(rules);
            }
        }

        if (rulesList.length > 1) {
            rulesList.sort((a, b) => b.length - a.length);
        }

        const targetRules = rulesList[0];

        const listForSELECTOR_COMMENT_GRAY_BOX = new Set();

        if (targetRules && targetRules.length > 300) {

            for (const rule of targetRules) {
                const cssText = rule.cssText;
                let classA = selfStaticClass(cutClass(cssText, "--comment-background"));
                if (classA) {
                    if (/^[\w-]*(\.[\w-]+)+$/.test(classA)) {
                        listForSELECTOR_COMMENT_GRAY_BOX.add(classA);
                    }
                }
                let classB = selfStaticClass(cutClass(cssText, "--comment-bubble"));
                if (classB) {
                    if (/^[\w-]*(\.[\w-]+)+$/.test(classB)) {
                        listForSELECTOR_COMMENT_GRAY_BOX.add(classB);
                    }
                }
            }
        }

        const SELECTOR_COMMENT_GRAY_BOX = [...listForSELECTOR_COMMENT_GRAY_BOX].join(",") || ".NO_SUCH_A_CLASS";

        // console.log(4001, { SELECTOR_COMMENT_GRAY_BOX })

        return { SELECTOR_COMMENT_GRAY_BOX };
    };

    // --------------------------

    let a0013 = STATE_INITIAL;

    setInterval(() => {
        if (a0013 === 0x0F11) {
            a0013 = STATE_INITIAL;
            // console.log(`set a0013 to ${a0013}`);
        }
    }, 350);


    let mDeferred = null;

    let clickWait = null;

    const rp = document.createElement("rp");

    const mutationLoop = async (callback) => {
        try {
            while (true) {
                let r = await callback();
                if (r) return;
                if (!mDeferred) mDeferred = deferred();
                await mDeferred.promise;
            }
        } catch (e) {
            console.error(e);
        }
    }

    let cid2 = 0;
    let cid5 = 0;
    let cidClick = 0;
    let clickHandler = null;
    const makeClickActionOn = (elm) => {
        const q = a0013;
        clickHandler = () => {
            clickHandler = null;
            if (a0013 !== q) return;
            elm.click();
            a0013 |= 1;
            // console.log(`set a0013 to ${a0013}`);
            document.documentElement.appendChild(rp).remove();
        };
        clearTimeout(cidClick);
        cidClick = setTimeoutQ(clickHandler, 80);
    }

    const delayedC2 = () => {

        a0013 = 0x012A;
        // console.log(`set a0013 to ${a0013}`);
        const text = getLangText();

        // requestAnimationFrame(() => {

        if (!SELECTOR_COMMENT_GRAY_BOX) {
            SELECTOR_COMMENT_GRAY_BOX = obtainClass().SELECTOR_COMMENT_GRAY_BOX;
        }

        let divs = getElementsByXPath(`//div[@role="button"]/span[starts-with(normalize-space(.), "${text["Most relevant"]}")]/parent::div`);
        divs = divs.filter((div) => {
            let parentLayout = getParentWith(div, SELECTOR_COMMENT_GRAY_BOX);
            if (!parentLayout) return false;
            return true;
        });

        if (!divs.length || a0013 !== 0x012A) {
            a0013 = 0x0100;
            return;
        }

        divs.forEach(div => {

            a0013 = (0x0200 | 0);
            // console.log(`set a0013 to ${a0013}`);
            const p = clickWait = deferred();
            makeClickActionOn(div);
            setTimeoutQ(() => {
                p.resolve();
            }, 120);
            // console.log("a0013", a0013);
            return true;
        });
        // });
    }

    const delayedC5 = () => {

        a0013 = 0x022A;
        // console.log(`set a0013 to ${a0013}`);
        const text = getLangText();

        // requestAnimationFrame(() => {

        if (!SELECTOR_COMMENT_GRAY_BOX) {
            SELECTOR_COMMENT_GRAY_BOX = obtainClass().SELECTOR_COMMENT_GRAY_BOX;
        }

        let menuitems = getElementsByXPath(`//div[@role="menuitem"]/div//span[starts-with(normalize-space(.), "${text["All comments"]}")]/ancestor::div[@role="menuitem"]`);
        menuitems = menuitems.filter((menuitem) => {
            let parentLayout = getParentWith(menuitem, SELECTOR_COMMENT_GRAY_BOX);
            if (!parentLayout) return false;
            return true;
        });

        if (!menuitems.length || a0013 !== 0x022A) {
            a0013 = 0x0100;
            return;
        }

        menuitems.forEach(menuitem => {

            if (a0013 !== 0x022A) return true;

            a0013 = (STATE_FINAL | 0);
            // console.log(`set a0013 to ${a0013}`);
            const p = clickWait = deferred();
            // console.log("a0013", a0013);
            makeClickActionOn(menuitem);
            setTimeoutQ(() => {
                p.resolve();
            }, 400);
            return true;

        });

        // });
    };

    startMonitor(async (mutations) => {

        if (!mutations || !mutations.length) return;

        if (mDeferred) {
            mDeferred.resolve();
            mDeferred = null;
        }

        if (clickHandler) {
            clearTimeout(cidClick);
            cidClick = setTimeoutQ(clickHandler, 80);
            // cidClick = 0;
        }

        if (a0013 === 0x0120) {
            clearTimeout(cid2);
            cid2 = setTimeoutQ(delayedC2, 40);
            // cid2 = 0;
        }
        else if (a0013 === 0x0220) {
            clearTimeout(cid5);
            cid5 = setTimeoutQ(delayedC5, 40);
            // cid5 = 0;
        } else if (a0013 === (STATE_FINAL | 1)) {
            a0013 = 0x0F10;
            // console.log(`set a0013 to ${a0013}`);
        }

        // let addedCount = 0;
        // for (const mutation of mutations) {
        //     for (const addedNode of mutation.addedNodes) {
        //         if (addedNode instanceof HTMLElement) {
        //             if (addedNode.isConnected === true) {
        //                 addedCount++;
        //             }
        //         }
        //     }
        // }
        // if (addedCount === 0) return;

        // if (clickHandler) {
        //     clearTimeout(cidClick);
        //     cidClick = setTimeoutQ(clickHandler, 80);
        // }

        if (clickWait) {
            await clickWait.promise;
        }

        if (a0013 === 0x0F10) {
            a0013 = 0x0F11;
            // console.log(`set a0013 to ${a0013}`);
        }

        const text = getLangText();
        if (a0013 === 0x0100) {
            const divs = getElementsByXPath(`//div[@role="button"]/span[starts-with(normalize-space(.), "${text["Most relevant"]}")]/parent::div`);
            if (divs.length > 0) {
                a0013 = 0x0120;
                // console.log(`set a0013 to ${a0013}`);
            }
        }

        if (a0013 === 0x0120) {
            clearTimeout(cid2);
            cid2 = setTimeoutQ(delayedC2, 40);
        }

        if (a0013 === (0x0200 | 1)) {
            const menuitems = getElementsByXPath(`//div[@role="menuitem"]/div//span[starts-with(normalize-space(.), "${text["All comments"]}")]/ancestor::div[@role="menuitem"]`);
            if (menuitems.length > 0) {
                a0013 = 0x0220;
                // console.log(`set a0013 to ${a0013}`);
            }
        }

        if (a0013 === 0x0220) {
            clearTimeout(cid5);
            cid5 = setTimeoutQ(delayedC5, 40);
        }

    });
    document.documentElement.appendChild(rp).remove();

})();