Greasyfork - Add notes to the script

Add notes (aliases/tags) for scripts to help identify and search

2023-02-27 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name                Greasyfork - Add notes to the script
// @name:zh-CN          Greasyfork - 为脚本添加备注(别名/标签)
// @name:zh-TW          Greasyfork - 為指令碼新增備註(別名/標籤)
// @namespace           https://greasyfork.org/zh-CN/users/193133-pana
// @homepage            https://greasyfork.org/zh-CN/users/193133-pana
// @icon                data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2JhKDI5LDE2MSwyNDIsMS4wMCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYmEoMjksMTYxLDI0MiwxLjAwKSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+
// @version             3.0.0
// @description         Add notes (aliases/tags) for scripts to help identify and search
// @description:zh-CN   为脚本添加备注(别名/标签)功能,以帮助识别和搜索
// @description:zh-TW   為指令碼新增備註(別名/標籤)功能,以幫助識別和搜尋
// @author              pana
// @license             GNU General Public License v3.0 or later
// @compatible          chrome
// @compatible          firefox
// @match               *://*.greasyfork.org/*
// @match               *://*.sleazyfork.org/*
// @require             https://gcore.jsdelivr.net/gh/LightAPIs/greasy-fork-library@05dffeb4eefb1a39df31d518cd45a4e6929929f3/Note_Obj.js
// @noframes
// @grant               GM_info
// @grant               GM_getValue
// @grant               GM_setValue
// @grant               GM_deleteValue
// @grant               GM_listValues
// @grant               GM_openInTab
// @grant               GM_addStyle
// @grant               GM_registerMenuCommand
// @grant               GM_unregisterMenuCommand
// @grant               GM_addValueChangeListener
// @grant               GM_removeValueChangeListener
// ==/UserScript==

(function () {
    'use strict';
    const UPDATED = '2023-02-27';
    const GF_ICON = {
        NOTE_BLACK: 'url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2IoMzgsIDM4LCAzOCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYigzOCwgMzgsIDM4KSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)',
    };
    const GF_STYLE = `
        .note-obj-gf-note-btn {
            background-image: ${GF_ICON.NOTE_BLACK};
            background-repeat: no-repeat;
            background-position: center;
            cursor: pointer;
            vertical-align: top;
        }
        .note-obj-gf-info-note-btn {
            background-size: 32px auto;
            width: 32px;
            height: 32px;
            margin-left: 20px;
            display: inline-block;
        }
        .note-obj-gf-library-note-btn {
            background-size: 24px auto;
            width: 24px;
            height: 24px;
            margin-left: 20px;
            display: inline-block;
        }
        .note-obj-gf-list-note-btn {
            background-size: 24px auto;
            width: 24px;
            height: 24px;
            margin-left: 10px;
            display: none;
        }
        .note-obj-gf-ts-note-btn {
            background-size: 16px auto;
            width: 16px;
            height: 16px;
            margin-left: 10px;
            display: none;
            vertical-align: sub;
        }
        ol.script-list li:hover .note-obj-gf-list-note-btn,
        #script-table tbody tr:hover .note-obj-gf-ts-note-btn {
            display: inline-block;
        }
        .note-obj-gf-note-tag,
        .note-obj-gf-ts-note-tag {
            background-color: #3c81df;
            color: #fff;
            display: inline-block;
            align-items: center;
            white-space: nowrap;
            border-radius: 50px;
            padding: 1px 10px;
            line-height: 1em;
        }
        .note-obj-gf-list-note-tag {
            text-decoration: none;
        }
    `;
    const noteObj = new Note_Obj({
        id: 'myGreasyForkNote',
        script: {
            author: {
                name: 'pana',
                homepage: 'https://greasyfork.org/zh-CN/users/193133-pana',
            },
            url: 'https://greasyfork.org/scripts/404275',
            updated: UPDATED,
        },
        itemClick: (key) => `${location.origin}/scripts/${key}`,
        language: {
            userIdText: {
                en: 'Script ID',
                zhHans: '脚本 ID',
                zhHant: '指令碼 ID',
            },
            userNameText: {
                en: 'Script name',
                zhHans: '脚本名',
                zhHant: '指令碼名',
            },
        },
        changeEvent,
        style: GF_STYLE,
    });
    function changeEvent(id) {
        const scriptId = getScriptIdFromPathname(location.pathname);
        if (scriptId) {
            infoPageNotes(scriptId, undefined, id);
        }
        else {
            listPageNotes(id);
            initTS(id);
        }
    }
    function initTS(changeId) {
        Note_Obj.fn.docQueryAll('#script-table tbody tr').forEach(item => {
            const scriptTitle = Note_Obj.fn.queryAnchor(item, '.thetitle a');
            if (scriptTitle) {
                const res = scriptTitle.href.match(/\d+$/);
                if (res) {
                    const scriptId = res[0];
                    const scriptName = scriptTitle.textContent?.trim();
                    const thetitle = Note_Obj.fn.query(item, '.thetitle');
                    if (thetitle && !Note_Obj.fn.query(thetitle, '.' + Note_Obj.btnClassName, 'none')) {
                        thetitle.appendChild(noteObj.createNoteBtn(scriptId, scriptName, ['note-obj-gf-note-btn', 'note-obj-gf-ts-note-btn']));
                    }
                    if (!changeId || changeId === scriptId) {
                        noteObj.handler(scriptId, scriptTitle, undefined, {
                            add: 'span',
                            className: ['note-obj-gf-ts-note-tag'],
                        }, scriptName);
                    }
                }
            }
        });
    }
    function getScriptIdFromPathname(pathname) {
        const res = pathname.match(/^\/[\w-]+\/scripts\/(\d+)-/);
        if (res && res.length === 2) {
            return res[1];
        }
        return null;
    }
    function infoPageNotes(scriptId, scriptName, changeId) {
        const ele = Note_Obj.fn.docQuery('#script-info h2', 'info');
        if (ele) {
            if (!changeId || changeId === scriptId)
                noteObj.handler(scriptId, ele, undefined, {
                    add: 'sapn',
                    className: ['note-obj-gf-note-tag'],
                }, scriptName);
        }
    }
    function listPageNotes(changeId) {
        const list = Note_Obj.fn.docQueryAll('ol.script-list li', 'info');
        for (const ele of list) {
            const scriptId = ele.dataset.scriptId;
            if (scriptId) {
                const description = Note_Obj.fn.query(ele, '.description');
                const scriptName = Note_Obj.fn.getText(ele, 'article > h2 > a', 'warn');
                if (description) {
                    const desParent = description.parentElement;
                    if (desParent && !Note_Obj.fn.query(desParent, '.' + Note_Obj.btnClassName, 'none')) {
                        description.before(noteObj.createNoteBtn(scriptId, scriptName, ['note-obj-gf-note-btn', 'note-obj-gf-list-note-btn']));
                    }
                }
                const header = Note_Obj.fn.query(ele, 'article > h2 > a');
                if (header) {
                    if (!changeId || changeId === scriptId)
                        noteObj.handler(scriptId, header, undefined, {
                            add: 'span',
                            className: ['note-obj-gf-note-tag', 'note-obj-gf-list-note-tag'],
                        }, scriptName);
                }
            }
        }
    }
    function init() {
        const scriptId = getScriptIdFromPathname(location.pathname);
        if (scriptId) {
            const installHelpLink = Note_Obj.fn.docQuery('#install-area .install-help-link:last-child', 'info');
            const scriptName = Note_Obj.fn.docGetText('header h2');
            if (installHelpLink) {
                installHelpLink.after(noteObj.createNoteBtn(scriptId, scriptName, ['note-obj-gf-note-btn', 'note-obj-gf-info-note-btn']));
            }
            else {
                const suggestion = Note_Obj.fn.docQuery('#script-feedback-suggestion');
                suggestion?.appendChild(noteObj.createNoteBtn(scriptId, scriptName, ['note-obj-gf-note-btn', 'note-obj-gf-library-note-btn']));
            }
            infoPageNotes(scriptId, scriptName);
        }
        else {
            listPageNotes();
            const scriptList = Note_Obj.fn.docQuery('#browse-script-list', 'info');
            if (scriptList) {
                const listObserver = new MutationObserver(() => {
                    listPageNotes();
                });
                listObserver.observe(scriptList, {
                    childList: true,
                });
            }
            initTS();
            const tsTbody = Note_Obj.fn.docQuery('#script-table tbody', 'none');
            if (tsTbody) {
                const tsObserver = new MutationObserver(() => {
                    initTS();
                });
                tsObserver.observe(tsTbody, {
                    childList: true,
                });
            }
        }
    }
    init();
})();