Greasy Fork镜像 Enhance

Enhance your experience at Greasyfork.

目前為 2023-08-04 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Greasy Fork镜像 Enhance
// @name:zh-CN   Greasy Fork镜像 增强
// @namespace    http://tampermonkey.net/
// @version      0.5.2
// @description  Enhance your experience at Greasyfork.
// @description:zh-CN 增进 Greasyfork 浏览体验。
// @author       PRO
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @match        https://gf.qytechs.cn/*
// @require      https://gf.qytechs.cn/scripts/470224-tampermonkey-config/code/Tampermonkey%20Config.js?version=1229665
// @icon         https://gf.qytechs.cn/vite/assets/blacklogo16-bc64b9f7.png
// @license      gpl-3.0
// ==/UserScript==

(function() {
    'use strict';
    // Judge if the script should run
    let no_run = [".json", ".js"];
    let is_run = true;
    let idPrefix = "greasyfork-enhance-";
    no_run.forEach((suffix) => {
        if (window.location.href.endsWith(suffix)) {
            is_run = false;
        }
    });
    if (!is_run) return;
    // Config
    let config_desc = {
        "auto-hide-code": {
            name: "Auto hide code",
            value: true,
            input: "current",
            processor: "not",
            formatter: "boolean"
        },
        "auto-hide-rows": {
            name: "Min rows to hide",
            value: 10,
            processor: "int_range-1-"
        },
        "flat-layout": {
            name: "Flat layout",
            value: false,
            input: "current",
            processor: "not",
            formatter: "boolean"
        },
    };
    let config = GM_config(config_desc);
    // Functions
    let body = document.querySelector("body");
    function sanitify(s) {
        // Remove emojis (such a headache)
        s = s.replaceAll(/([\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2580-\u27BF]|\uD83E[\uDD10-\uDEFF]|\uFE0F)/g, "");
        // Trim spaces and newlines
        s = s.trim();
        // Replace spaces
        s = s.replaceAll(" ", "-");
        s = s.replaceAll("%20", "-");
        // No more multiple "-"
        s = s.replaceAll(/-+/g, "-");
        return s;
    }
    function process(node) { // Add anchor and assign id to given node; Add to outline. Return true if node is actually processed.
        if (node.childElementCount > 1 || node.classList.length > 0) return false; // Ignore complex nodes
        let text = node.textContent;
        node.id = sanitify(text); // Assign id
        // Add anchors
        let node_ = document.createElement('a');
        node_.className = 'anchor';
        node_.href = '#' + node.id;
        node.appendChild(node_);
        let list_item = document.createElement("li");
        outline.appendChild(list_item);
        let link = document.createElement("a");
        link.href = "#" + node.id;
        link.text = text;
        list_item.appendChild(link);
        return true;
    }
    function copyCode() {
        let code = this.parentNode.nextElementSibling;
        let text = code.textContent;
        navigator.clipboard.writeText(text).then(() => {
            this.textContent = "Copied!";
            setTimeout(() => {
                this.textContent = "Copy code";
            }, 1000);
        });
    }
    function toggleCode() {
        let code = this.parentNode.nextElementSibling;
        if (code.style.display == "none") {
            code.style.display = "";
            this.textContent = "Hide code";
        } else {
            code.style.display = "none";
            this.textContent = "Show code";
        }
    }
    function create_toolbar() {
        let toolbar = document.createElement("div");
        let copy = document.createElement("a");
        let toggle = document.createElement("a");
        toolbar.appendChild(copy);
        toolbar.appendChild(toggle);
        copy.textContent = "Copy code";
        copy.className = "code-operation";
        copy.title = "Copy code to clipboard";
        copy.addEventListener("click", copyCode);
        toggle.textContent = "Hide code";
        toggle.className = "code-operation";
        toggle.title = "Toggle code display";
        toggle.addEventListener("click", toggleCode);
        // Css
        toolbar.className = "code-toolbar";
        return toolbar;
    }
    function cssHelper(id, css) {
        let current = document.getElementById(idPrefix + id);
        if (css && !current) {
            let style = document.createElement("style");
            style.id = idPrefix + id;
            style.textContent = css;
            document.head.appendChild(style);
        } else if (!css && current) {
            current.remove();
        }
    }
    // Css
    let css = document.createElement("style");
    css.textContent = `
    html {
        scroll-behavior: smooth;
    }
    a.anchor::before {
        content: "#";
    }
    a.anchor {
        opacity: 0;
        text-decoration: none;
        padding: 0px 0.5em;
        -moz-transition: all 0.25s ease-in-out;
        -o-transition: all 0.25s ease-in-out;
        -webkit-transition: all 0.25s ease-in-out;
        transition: all 0.25s ease-in-out;
    }
    h1:hover>a.anchor,
    h2:hover>a.anchor,
    h3:hover>a.anchor,
    h4:hover>a.anchor,
    h5:hover>a.anchor,
    h6:hover>a.anchor {
        opacity: 1;
        -moz-transition: all 0.25s ease-in-out;
        -o-transition: all 0.25s ease-in-out;
        -webkit-transition: all 0.25s ease-in-out;
        transition: all 0.25s ease-in-out;
    }
    a.button {
        margin: 0.5em 0 0 0;
        display: flex;
        align-items: center;
        justify-content: center;
        text-decoration: none;
        color: black;
        background-color: #a42121ab;
        border-radius: 50%;
        width: 2em;
        height: 2em;
        font-size: 1.8em;
        font-weight: bold;
    }
    div.code-toolbar {
        display: flex;
        gap: 1em;
    }
    a.code-operation {
        cursor: pointer;
        font-style: italic;
    }
    div.lum-lightbox {
        z-index: 2;
    }
    div#float-buttons {
        position: fixed;
        bottom: 1em;
        right: 1em;
        display: flex;
        flex-direction: column;
        user-select: none;
        z-index: 1;
    }
    aside.panel {
        display: none;
    }
    .dynamic-opacity {
        transition: opacity 0.2s ease-in-out;
        opacity: 0.2;
    }
    .dynamic-opacity:hover {
        opacity: 0.8;
    }
    input[type=file] {
        border-style: dashed;
        border-radius: 0.5em;
        padding: 0.5em;
        background: rgba(169, 169, 169, 0.4);
    }
    table {
        border: 1px solid #8d8d8d;
        border-collapse: collapse;
        width: auto;
    }
    table td, table th {
        padding: 0.5em 0.75em;
        vertical-align: middle;
        border: 1px solid #8d8d8d;
    }
    @media (any-hover: none) {
        .dynamic-opacity {
            opacity: 0.8;
        }
        .dynamic-opacity:hover {
            opacity: 0.8;
        }
    }
    @media screen and (min-width: 767px) {
        aside.panel {
            display: contents;
            line-height: 1.5;
        }
        ul.outline {
            position: sticky;
            float: right;
            padding: 0 0 0 0.5em;
            margin: 0 0.5em;
            max-height: 80vh;
            border: 1px solid #BBBBBB;
            border-left: 2px solid #F2E5E5;
            box-shadow: 0 0 5px #ddd;
            background: linear-gradient(to right, #fcf1f1, #FFF 1em);
            list-style: none;
            width: 10.5%;
            color: gray;
            border-radius: 5px;
            overflow-y: scroll;
            z-index: 1;
        }
        ul.outline > li {
            overflow: hidden;
            text-overflow: ellipsis;
        }
        ul.outline > li > a {
            color: gray;
            white-space: nowrap;
            text-decoration: none;
        }
    }`;
    document.querySelector("head").appendChild(css); // Inject css
    // Aside panel & Anchors
    let outline;
    let is_script = /^\/[^\/]+\/scripts/;
    let is_specific_script = /^\/[^\/]+\/scripts\/\d+/;
    let is_disccussion = /^\/[^\/]+\/discussions/;
    let path = window.location.pathname;
    if ((!is_script.test(path) && !is_disccussion.test(path)) || is_specific_script.test(path)) {
        let panel = document.createElement("aside");
        panel.className = "panel";
        body.insertBefore(panel, document.querySelector("body > div.width-constraint"));
        let reference_node = document.querySelector("body > div.width-constraint > section");
        outline = document.createElement("ul");
        outline.classList.add("outline");
        outline.classList.add("dynamic-opacity");
        outline.style.top = reference_node ? getComputedStyle(reference_node).marginTop : "1em";
        outline.style.marginTop = outline.style.top;
        panel.appendChild(outline);
        let flag = false;
        document.querySelectorAll("body > div.width-constraint h1, h2, h3, h4, h5, h6").forEach((node) => {
            flag = process(node) || flag; // Not `flag || process(node)`!
        });
        if (!flag) {
            panel.remove();
        }
    }
    // Navigate to hash
    let hash = window.location.hash.slice(1);
    if (hash) {
        let ele = document.getElementById(decodeURIComponent(hash));
        if (ele) {
            ele.scrollIntoView();
        }
    }
    // Buttons
    let buttons = document.createElement("div");
    buttons.id = "float-buttons";
    let to_top = document.createElement("a");
    to_top.classList.add("button");
    to_top.classList.add("dynamic-opacity");
    to_top.href = "#top";
    to_top.text = "↑";
    buttons.appendChild(to_top);
    body.appendChild(buttons);
    // Double click to get to top
    body.addEventListener("dblclick", (e) => {
        if (e.target === body) {
            to_top.click();
        }
    });
    // Fix current tab link
    let tab = document.querySelector("ul#script-links > li.current");
    if (tab) {
        let link = document.createElement("a");
        link.href = window.location.pathname;
        let orig_child = tab.firstChild;
        link.appendChild(orig_child);
        tab.appendChild(link);
    }
    let parts = window.location.pathname.split("/");
    if (parts.length <= 2 || (parts.length == 3 && parts[2] === '')) {
        let banner = document.querySelector("header#main-header div#site-name");
        let img = banner.querySelector("img");
        let text = banner.querySelector("#site-name-text > h1");
        let link1 = document.createElement("a");
        link1.href = window.location.pathname;
        img.parentNode.replaceChild(link1, img);
        link1.appendChild(img);
        let link2 = document.createElement("a");
        link2.href = window.location.pathname;
        link2.textContent = text.textContent;
        text.textContent = "";
        text.appendChild(link2);
    }
    // Toolbar for code blocks
    let code_blocks = document.getElementsByTagName("pre");
    let auto_hide = config["auto-hide-code"];
    let auto_hide_rows = config["auto-hide-rows"];
    for (let code_block of code_blocks) {
        code_block.insertAdjacentElement("afterbegin", create_toolbar());
    }
    // Auto hide code blocks
    function autoHide() {
        if (!auto_hide) {
            for (let code_block of code_blocks) {
                let toggle = code_block.firstChild.lastChild;
                if (toggle.textContent === "Show code") {
                    toggle.click(); // Click the toggle button
                }
            }
        } else {
            for (let code_block of code_blocks) {
                let m = code_block.lastChild.textContent.match(/\n/g);
                let rows = m ? m.length : 0;
                let toggle = code_block.firstChild.lastChild;
                let hidden = toggle.textContent === "Show code";
                if (rows >= auto_hide_rows && !hidden || rows < auto_hide_rows && hidden) {
                    code_block.firstChild.lastChild.click(); // Click the toggle button
                }
            }
        }
    }
    autoHide();
    // Flat layout
    function flatLayout(enabled) {
        let css = `
        .script-list li:not(.ad-entry) {
            padding: 1em 0 0.5em 1em;
        }
        ol.script-list > li > article {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            align-items: center;
        }
        ol.script-list > li > article > h2 {
            width: 60%;
            overflow: hidden;
            text-overflow: ellipsis;
            margin-right: 0.5em;
            padding-right: 0.5em;
            border-right: 1px solid #DDDDDD;
        }
        .showing-all-languages .badge-js, .showing-all-languages .badge-css, .script-type {
            display: none;
        }
        ol.script-list > li > article > h2 > a.script-link {
            white-space: nowrap;
        }
        ol.script-list > li > article > h2 > span.script-description {
            display: block;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        ol.script-list > li > article > div.script-meta-block {
            width: 40%;
            column-gap: 0;
        }
        ol.script-list > li > article > div.script-meta-block > dl.inline-script-stats > dd {
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        `;
        cssHelper("flat-layout", enabled ? css : null);
    }
    flatLayout(config["flat-layout"]);
    // Dynamically respond to config changes
    let callbacks = {
        "auto-hide-code": (after) => {
            auto_hide = after;
            autoHide();
        },
        "auto-hide-rows": (after) => {
            auto_hide_rows = after;
            autoHide();
        },
        "flat-layout": flatLayout,
    };
    window.addEventListener(GM_config_event, e => {
        if (e.detail.type === "set") {
            let callback = callbacks[e.detail.prop];
            if (callback && (e.detail.before !== e.detail.after)) {
                callback(e.detail.after);
            }
        }
    });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址