Greasy Fork is available in English.

AO3: [Wrangling] All Action Buttons in Tag Bins

Freely configure the "manage" buttons for tags in the bin

// ==UserScript==
// @name         AO3: [Wrangling] All Action Buttons in Tag Bins
// @namespace    https://greasyfork.org/en/users/906106-escctrl
// @description  Freely configure the "manage" buttons for tags in the bin
// @author       escctrl
// @match        *://*.archiveofourown.org/tags/*/wrangle*
// @version      2.3
// @license      MIT
// @grant        none
// ==/UserScript==

/* *************************************************
   !!! IMPORTANT !!!
   This script might not play well with others, if they expect action buttons in a certain order or with certain labels.
   To work with other scripts that add more buttons to the list, this script needs to run first. So make sure it is at the top of the order of your installed scripts.
   Ping me if you need help getting this to cooperate with another script.
************************************************* */

// CONFIGURATION
    // whether to use icons or text for all the action buttons (true = icons, false = text)
    const ICONIFY = true;

    // the following types of action buttons are available:
    // "landing", "edit", "comments", "works", "bookmarks", "remove", "tagname", "taglink"
    // add or remove them from the list to control which action buttons are shown
    // reorder within the list to change the order in which they appear on the pages
    const button_list = ["edit", "comments", "works", "taglink"];


(function() {
    'use strict';

    // code from adustyspectacle's script (https://greasyfork.org/scripts/30563)
    // This section here is to load FontAwesome so the icons will properly render
    if (ICONIFY) {
        var font_awesome_icons = document.createElement('script');
        font_awesome_icons.setAttribute('src', 'https://use.fontawesome.com/ed555db3cc.js');
        document.getElementsByTagName('head')[0].appendChild(font_awesome_icons);

        var fa_icons_css = document.createElement('style');
        fa_icons_css.setAttribute('type', 'text/css');
        fa_icons_css.innerHTML = "tbody td ul.actions { font-family: FontAwesome, sans-serif; } tbody td .actions input[type='checkbox'] { margin: auto auto auto 0.5em; vertical-align: bottom; }";
        document.getElementsByTagName('head')[0].appendChild(fa_icons_css);
    }

    const button_data = {
        landing:  { link: "",
                    icon: "",
                    text: "Landing Page",
                    tooltip: "Tag Landing Page" },
        edit:     { link: "/edit",
                    icon: "",
                    text: "Edit",
                    tooltip: "Edit tag" },
        comments: { link: "/comments",
                    icon: "",
                    text: "Comments",
                    tooltip: "Comments" },
        works:    { link: "/works",
                    icon: "",
                    text: "Works",
                    tooltip: "Works" },
        bookmarks:{ link: "/bookmarks",
                    icon: "",
                    text: "Bookmarks",
                    tooltip: "Bookmarks" },
        remove:   { link: "",
                    icon: "",
                    text: "Remove",
                    tooltip: "Remove from fandom" },
        taglink:  { link: "" ,
                    icon: "",
                    text: "Copy Link",
                    tooltip: "Copy link" },
        tagname:  { link: "" ,
                    icon: "",
                    text: "Copy Name",
                    tooltip: "Copy tag name" }
    };

    // cycling through the table lines
    var lines = document.querySelectorAll('#wrangulator table tbody tr');

    // if the page is status=unwrangled, we'll skip the remove button since those tags aren't yet attached to the fandom
    const searchParams = new URLSearchParams(window.location.search);
    const unwrangled = (searchParams.get('status') == "unwrangled") ? true : false;

    for (let i of lines) {
        // get a plain link from the /works link (always last link on a vanilla page) and removing the /works part XD
        var plainlink = i.querySelector('td:last-of-type li:last-child a').href.slice(0, -6);

        var buttons = document.createElement('ul');
        buttons.classList.add('actions');

        // create the buttons in user-defined order
        for (let v of button_list) {
            var button = document.createElement('li');
            button.title = button_data[v].tooltip;

            var title = (ICONIFY) ? button_data[v].icon : button_data[v].text;
            var href = plainlink + button_data[v].link;

            if (v == "remove") {
                if (unwrangled) break;
                // grab the existing remove button (easier than trying to build it TBH) which is always first on the vanilla wrangulator
                // + replace the vanilla Remove label (in this capitalization, otherwise we'd replace some element attributes) with our preferred button text
                button.innerHTML = i.querySelector('ul.actions li:first-child').innerHTML.replace(/Remove/, title);
            }
            // button for copying the tag name/link is a very special case :)
            else if (v == "taglink" || v == "tagname") {
                const tag_name = i.querySelector('th label').innerText;
                button.innerHTML = (v == "taglink") ? `<a href="javascript:void(0);">${title}</a><span style="display: none;"><a href="${href}">${tag_name}</a></span>`
                                                    : `<a href="javascript:void(0);">${title}</a><span style="display: none;">${tag_name}</span>`;

                button.addEventListener("click", function(e) {
                    const val = e.target.parentNode.title;
                    var str = e.target.parentNode.querySelector('span');
                    str = (val == button_data.taglink.tooltip) ? str.innerHTML : str.innerText;
                    copy2Clipboard(e, str);
                    return false;
                });
            }
            // all others are simple...
            else button.innerHTML = `<a href="${href}">${title}</a>`;

            buttons.appendChild(button);
        }
        // let's also add a hidden edit button (exactly as the vanilla page) as the first button, so that other scripts don't throw errors
        var oldschooledit = new URL(`${plainlink}/edit`);
        button = document.createElement('li');
        button.setAttribute("style", "display: none;");
        button.innerHTML = `<a href="${oldschooledit.pathname}">Edit</a>`;
        buttons.insertBefore(button, buttons.children[0]);

        // replace the existing buttons with the desired ones
        var parent = i.querySelector('td:last-child');
        parent.replaceChild(buttons, parent.firstElementChild);
    }

})();


// solution for setting richtext clipboard content found at https://jsfiddle.net/jdhenckel/km7prgv4/3/
// and https://stackoverflow.com/questions/34191780/javascript-copy-string-to-clipboard-as-text-html/74216984#74216984
function copy2Clipboard(e, str) {
    // trying first with the new Clipboard API
    try {
        const clipboardItem = new ClipboardItem({'text/html': new Blob([str], {type: 'text/html'}),
                                                 'text/plain': new Blob([str], {type: 'text/plain'})});
        navigator.clipboard.write([clipboardItem]);
    }
    // fallback method in case clipboard.write is not enabled - especially in Firefox it's disabled by default
    // to enable, go to about:config and turn dom.events.asyncClipboard.clipboardItem to true
    catch {
        console.log('Copy Tag to Clipboard: Clipboard API is not enabled in your browser - fallback option used');
        function listener(e) {
            e.clipboardData.setData("text/html", str);
            e.clipboardData.setData("text/plain", str);
            e.preventDefault();
        }
        document.addEventListener("copy", listener);
        document.execCommand("copy");
        document.removeEventListener("copy", listener);
    }
}