Facebook Switch to All comments

To switch Facebook to All comments

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

You will need to install an extension such as Tampermonkey to install this script.

이 스크립트를 설치하려면 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();

})();