Greasy Fork is available in English.

PTT網頁版樓層擴充

PTT網頁版的樓層擴充套件

// ==UserScript==
// @name         PTT網頁版樓層擴充
// @namespace    https://www.ptt.cc/
// @version      1.6
// @description  PTT網頁版的樓層擴充套件
// @author       Anisile
// @match        https://www.ptt.cc/bbs*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ptt.cc
// @license      GPL
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// ==/UserScript==

(function() {
    'use strict';

    const items = document.querySelectorAll(".push");
    const authorHighlight = AuthorHighlightInit ();
    const authorID = GetAuthorID ();

    // ========新增CSS========
    AddStyle (
        `.floor {
            float: right;
        }
        .hover {
            background-color: #222222;
        }
        .highlight {
            background-color: #333333;
        }
        .authorHighlight {
            background-color: blue;
        }
        .targetFloor {
            background-color: #444444 !important;
        }`
    )

    var i = 1;
    items.forEach((item) => {
        // ========顯示樓層========
        const child = document.createElement ("span");
        child.classList.add ("floor");
        child.innerHTML = `${i}樓`.padStart (6, " ");
        item.insertBefore (child, item.lastChild);
        item.setAttribute("id", `floor${i}`);
        i++;

        // ========同使用者留言上色========
        item.addEventListener("mouseover", function (e){
            OnMouseOverFloor (e);
        });
        item.addEventListener("mouseleave", function (e){
            OnMouseLeaveFloor (e);
        });
        item.addEventListener("click", function (e){
            OnMouseClickFloor (e);
        });

        // ========原作者ID上色========
        if (authorHighlight) {
            const user = item.querySelector('.push-userid');
            if (user.innerHTML === authorID) {
                user.classList.add ("authorHighlight");
            }
        }
    });

    // ========搜尋樓層========
    var form = document.createElement ("form");
    var label = document.createElement ("label");
    var floor = document.createElement("input");
    floor.setAttribute("type", "text");
    floor.setAttribute("name", "floor");
    floor.setAttribute("autocomplete", "off");
    floor.setAttribute("placeholder", "輸入想跳轉的樓層");

    label.setAttribute("for", "floor");
    label.style.fontSize = "16px";
    label.innerHTML = "歡迎搭乘電梯:";

    form.append (label);
    form.append (floor);
    form.addEventListener('submit', function (e){
        GoToFloor (e);
    });
    document.getElementById ("navigation").appendChild (form);

    // ========直達頂樓========
    var goToTop = document.createElement ("a");
    goToTop.innerHTML = '直達頂樓';
    goToTop.style.cursor = "pointer";
    goToTop.onclick = function () {
        GoToTop ();
    };
    document.getElementById ("navigation").appendChild (goToTop);

    // ========功能區========
    function AddStyle (css) {
        var style = document.createElement('style');
        style.type = 'text/css';
        style.appendChild(document.createTextNode(css));
        document.head.appendChild (style);
    }

    function GoToFloor (e) {
        e.preventDefault();

        var submit = floor.value;
        if (isNaN (submit)) {
            window.alert("請填入數字");
            return false;
        }
        console.log (`跳轉到${submit}樓`);
        try {
            var result = document.getElementById(`floor${submit}`);
            result.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" });
            result.classList.add ("targetFloor");
            setTimeout(() => {
                result.classList.remove ("targetFloor");
            }, 3000);
        }
        catch (err) {
            console.log (err);
        }
        return false;
    }

    function OnMouseOverFloor (e) {
        const user = e.currentTarget.querySelector('.push-userid').innerHTML;
        items.forEach((item) => {
            if (user === item.querySelector('.push-userid').innerHTML) {
                item.classList.add ("hover");
            }
            else {
                item.classList.remove ("hover");
            }
        });
    }

    function OnMouseLeaveFloor (e) {
        items.forEach((item) => {
            item.classList.remove ("hover");
        });
    }

    function OnMouseClickFloor (e) {
        const hasHighlight = e.currentTarget.classList.contains ("highlight");
        const user = e.currentTarget.querySelector('.push-userid').innerHTML;
        if (hasHighlight) {
            items.forEach((item) => {
                if (item.classList.contains ("highlight")) {
                    item.classList.remove ("highlight");
                }
            });
        }
        else {
            items.forEach((item) => {
                if (user === item.querySelector('.push-userid').innerHTML) {
                    item.classList.add ("highlight");
                }
                else {
                    item.classList.remove ("highlight");
                }
            });
        }
    }

    function GoToTop () {
        document.body.scrollTop = 0;
        document.documentElement.scrollTop = 0;
    }

    function AuthorHighlightInit () {
        let menuId;

        function open() {
            GM_unregisterMenuCommand (menuId);
            localStorage.setItem ("authorHighlight", "true");
            location.reload ();
        }
        function close() {
            GM_unregisterMenuCommand (menuId);
            localStorage.setItem ("authorHighlight", "false");
            location.reload ();
        }

        let authorHighlight = localStorage.getItem ("authorHighlight");
        if (!authorHighlight || authorHighlight === "false") {
            menuId = GM_registerMenuCommand ("開啟作者ID上色", open);
        }
        else if (authorHighlight === "true") {
            menuId = GM_registerMenuCommand ("關閉作者ID上色", close);
        }
        return authorHighlight === "true";
    }

    function GetAuthorID () {
        let authorID = "";
        const collection = document.getElementsByClassName ("article-metaline");
        Array.from (collection).forEach ((item) => {
            if (item.querySelector ('.article-meta-tag').innerHTML === "作者") {
                const author = item.querySelector ('.article-meta-value').innerHTML;
                authorID = author.substring (0, author.indexOf(' '));
            }
        });
        return authorID;
    }
})();