Skip to content

[Feature] Double-struck (blackboard bold) font #811

@AcesGamingUK

Description

@AcesGamingUK

Which plugin/theme is this about?
BFRedux

Describe the feature you'd like
A new option called Double-struck

Additional context
I have already added it to my end so I can use it, (might need some cleaning up. but it works fine in my testing, would love to see it officially added so I don't have to keep reading it on updates.
You can look here, I have added the lines to the .js file 74-79, 173-178, 231-237, 477,541-544, 881

BetterFormattingRedux.plugin.js
/**
 * @name BetterFormattingRedux
 * @description Enables different types of formatting in standard Discord chat.
 * @version 2.3.14
 * @author Zerebos
 * @authorId 249746236008169473
 * @website https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/BetterFormattingRedux
 * @source https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/BetterFormattingRedux/BetterFormattingRedux.plugin.js
 */
/*@cc_on
@if (@_jscript)
    
    // Offer to self-install for clueless users that try to run this directly.
    var shell = WScript.CreateObject("WScript.Shell");
    var fs = new ActiveXObject("Scripting.FileSystemObject");
    var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins");
    var pathSelf = WScript.ScriptFullName;
    // Put the user at ease by addressing them in the first person
    shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
    if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
        shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40);
    } else if (!fs.FolderExists(pathPlugins)) {
        shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10);
    } else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) {
        fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
        // Show the user where to put plugins in the future
        shell.Exec("explorer " + pathPlugins);
        shell.Popup("I'm installed!", 0, "Successfully installed", 0x40);
    }
    WScript.Quit();

@else@*/
const config = {
    info: {
        name: "BetterFormattingRedux",
        authors: [
            {
                name: "Zerebos",
                discord_id: "249746236008169473",
                github_username: "rauenzi",
                twitter_username: "ZackRauen"
            }
        ],
        version: "2.3.14",
        description: "Enables different types of formatting in standard Discord chat.",
        github: "https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/BetterFormattingRedux",
        github_raw: "https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/BetterFormattingRedux/BetterFormattingRedux.plugin.js"
    },
    changelog: [
        {
            title: "GUI Works Again",
            type: "fixed",
            items: [
                "Clicking the buttons works again!",
                "Dragging to reorder the buttons is broken."
            ]
        }
    ],
    main: "index.js",
    defaultConfig: [
        {
            type: "category",
            id: "toolbar",
            name: "Toolbar Buttons",
            collapsible: true,
            shown: false,
            settings: [
                {
                    type: "switch",
                    id: "bold",
                    name: "Bold",
                    value: true
                },
                {
                    type: "switch",
                    id: "doublestruck",
                    name: "Double Struck",
                    value: true
                },
                {
                    type: "switch",
                    id: "italic",
                    name: "Italic",
                    value: true
                },
                {
                    type: "switch",
                    id: "underline",
                    name: "Underline",
                    value: true
                },
                {
                    type: "switch",
                    id: "strikethrough",
                    name: "Strikethrough",
                    value: true
                },
                {
                    type: "switch",
                    id: "spoiler",
                    name: "Spoiler",
                    value: true
                },
                {
                    type: "switch",
                    id: "code",
                    name: "Code",
                    value: true
                },
                {
                    type: "switch",
                    id: "codeblock",
                    name: "Codeblock",
                    value: true
                },
                {
                    type: "switch",
                    id: "superscript",
                    name: "Superscript",
                    value: true
                },
                {
                    type: "switch",
                    id: "smallcaps",
                    name: "Smallcaps",
                    value: true
                },
                {
                    type: "switch",
                    id: "fullwidth",
                    name: "Full Width",
                    value: true
                },
                {
                    type: "switch",
                    id: "upsidedown",
                    name: "Upsidedown",
                    value: true
                },
                {
                    type: "switch",
                    id: "varied",
                    name: "Varied Caps",
                    value: true
                },
                {
                    type: "switch",
                    id: "leet",
                    name: "Leet (1337)",
                    value: false
                },
                {
                    type: "switch",
                    id: "thicc",
                    name: "Extra Thicc",
                    value: false
                }
            ]
        },
        {
            type: "category",
            id: "formats",
            name: "Active Formats",
            collapsible: true,
            shown: false,
            settings: [
                {
                    type: "switch",
                    id: "superscript",
                    name: "Superscript",
                    value: true
                },
                {
                    type: "switch",
                    id: "doublestruck",
                    name: "Double Struck",
                    value: true
                },
                {
                    type: "switch",
                    id: "smallcaps",
                    name: "Smallcaps",
                    value: true
                },
                {
                    type: "switch",
                    id: "fullwidth",
                    name: "Full Width",
                    value: true
                },
                {
                    type: "switch",
                    id: "upsidedown",
                    name: "Upsidedown",
                    value: true
                },
                {
                    type: "switch",
                    id: "varied",
                    name: "Varied Caps",
                    value: true
                },
                {
                    type: "switch",
                    id: "leet",
                    name: "Leet (1337)",
                    value: false
                },
                {
                    type: "switch",
                    id: "thicc",
                    name: "Extra Thicc",
                    value: false
                }
            ]
        },
        {
            type: "category",
            id: "wrappers",
            name: "Wrapper Options",
            collapsible: true,
            shown: false,
            settings: [
                {
                    type: "textbox",
                    id: "superscript",
                    name: "Superscript",
                    note: "The wrapper for superscripted text",
                    value: "^^"
                },
                {
                    type: "textbox",
                    id: "doublestruck",
                    name: "Double Struck",
                    note: "The wrapper for double-struck text",
                    value: ".."
                },
                {
                    type: "textbox",
                    id: "smallcaps",
                    name: "Smallcaps",
                    note: "The wrapper to make Smallcaps.",
                    value: "%%"
                },
                {
                    type: "textbox",
                    id: "fullwidth",
                    name: "Full Width",
                    note: "The wrapper for E X P A N D E D  T E X T.",
                    value: "##"
                },
                {
                    type: "textbox",
                    id: "upsidedown",
                    name: "Upsidedown",
                    note: "The wrapper to flip the text upsidedown.",
                    value: "&&"
                },
                {
                    type: "textbox",
                    id: "varied",
                    name: "Varied Caps",
                    note: "The wrapper to VaRy the capitalization.",
                    value: "=="
                },
                {
                    type: "textbox",
                    id: "leet",
                    name: "Leet (1337)",
                    note: "The wrapper to talk in 13375p34k.",
                    value: "++"
                },
                {
                    type: "textbox",
                    id: "thicc",
                    name: "Extra Thicc",
                    note: "The wrapper to get 乇乂下尺卂 下卄工匚匚.",
                    value: "$$"
                }
            ]
        },
        {
            type: "category",
            id: "formatting",
            name: "Formatting Options",
            collapsible: true,
            shown: false,
            settings: [
                {
                    type: "dropdown",
                    id: "fullWidthMap",
                    name: "Fullwidth Style",
                    note: "Which style of fullwidth formatting should be used.",
                    value: true,
                    options: [
                        {
                            label: "T H I S",
                            value: false
                        },
                        {
                            label: "this",
                            value: true
                        }
                    ]
                },
                {
                    type: "switch",
                    id: "reorderUpsidedown",
                    name: "Reorder Upsidedown Text",
                    note: "Having this enabled reorders the upside down text to make it in-order.",
                    value: true
                },
                {
                    type: "switch",
                    id: "fullwidth",
                    name: "Start VaRiEd Caps With Capital",
                    note: "Enabling this starts a varied text string with a capital.",
                    value: true
                }
            ]
        },
        {
            type: "category",
            id: "plugin",
            name: "Functional Options",
            collapsible: true,
            shown: false,
            settings: [
                {
                    type: "dropdown",
                    id: "hoverOpen",
                    name: "Opening Toolbar",
                    note: "Determines when to show the toolbar.",
                    value: true,
                    options: [
                        {
                            label: "Click",
                            value: false
                        },
                        {
                            label: "Hover",
                            value: true
                        }
                    ]
                },
                {
                    type: "dropdown",
                    id: "chainFormats",
                    name: "Format Chaining",
                    note: "Swaps priority of wrappers between inner first and outer first. Check the GitHub for more info.",
                    value: true,
                    options: [
                        {
                            label: "Inner",
                            value: false
                        },
                        {
                            label: "Outer",
                            value: true
                        }
                    ]
                },
                {
                    type: "switch",
                    id: "closeOnSend",
                    name: "Close On Send",
                    note: "This option will close the toolbar when a message is sent.",
                    value: true
                }
            ]
        },
        {
            type: "category",
            id: "style",
            name: "Style Options",
            collapsible: true,
            shown: false,
            settings: [
                {
                    type: "dropdown",
                    id: "icons",
                    name: "Toolbar Style",
                    note: "Switches between icons and text as the toolbar buttons.",
                    value: true,
                    options: [
                        {
                            label: "Text",
                            value: false
                        },
                        {
                            label: "Icons",
                            value: true
                        }
                    ]
                },
                {
                    type: "dropdown",
                    id: "rightSide",
                    name: "Toolbar Location",
                    note: "This option enables swapping toolbar location.",
                    value: true,
                    options: [
                        {
                            label: "Left",
                            value: false
                        },
                        {
                            label: "Right",
                            value: true
                        }
                    ]
                },
                {
                    type: "slider",
                    id: "toolbarOpacity",
                    name: "Opacity",
                    note: "This allows the toolbar to be partially seethrough.",
                    value: 1,
                    min: 0,
                    max: 1
                },
                {
                    type: "slider",
                    id: "fontSize",
                    name: "Font Size",
                    note: "Adjusts the font size between 0 and 100%.",
                    value: 85,
                    min: 0,
                    max: 100
                }
            ]
        }
    ]
};
class Dummy {
    constructor() {this._config = config;}
    start() {}
    stop() {}
}
 
if (!global.ZeresPluginLibrary) {
    BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.name ?? config.info.name} is missing. Please click Download Now to install it.`, {
        confirmText: "Download Now",
        cancelText: "Cancel",
        onConfirm: () => {
            require("request").get("https://betterdiscord.app/gh-redirect?id=9", async (err, resp, body) => {
                if (err) return require("electron").shell.openExternal("https://betterdiscord.app/Download?id=9");
                if (resp.statusCode === 302) {
                    require("request").get(resp.headers.location, async (error, response, content) => {
                        if (error) return require("electron").shell.openExternal("https://betterdiscord.app/Download?id=9");
                        await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), content, r));
                    });
                }
                else {
                    await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r));
                }
            });
        }
    });
}
 
module.exports = !global.ZeresPluginLibrary ? Dummy : (([Plugin, Api]) => {
     const plugin = (Plugin, Api) => {
    const {ContextMenu, DOM, Patcher, UI} = window.BdApi;
    const {DiscordSelectors, PluginUtilities, DiscordModules, Utilities, ReactTools} = Api;

    return class BetterFormattingRedux extends Plugin {
        constructor() {
            super();
            this.isOpen = false;
            this.replaceList = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}";
            this.smallCapsList = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`ᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ{|}";
            this.superscriptList = " !\"#$%&'⁽⁾*⁺,⁻./⁰¹²³⁴⁵⁶⁷⁸⁹:;<⁼>?@ᴬᴮᶜᴰᴱᶠᴳᴴᴵᴶᴷᴸᴹᴺᴼᴾQᴿˢᵀᵁνᵂˣʸᶻ[\\]^_`ᵃᵇᶜᵈᵉᶠᵍʰᶦʲᵏˡᵐⁿᵒᵖᑫʳˢᵗᵘᵛʷˣʸᶻ{|}";
            this.upsideDownList = " ¡\"#$%℘,)(*+'-˙/0ƖᄅƐㄣϛ9ㄥ86:;>=<¿@∀qƆpƎℲפHIſʞ˥WNOԀQɹS┴∩ΛMXλZ]\\[^‾,ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz}|{";
            this.fullwidthList = " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}";
            this.leetList = " !\"#$%&'()*+,-./0123456789:;<=>?@48CD3FG#IJK1MN0PQЯ57UVWXY2[\\]^_`48cd3fg#ijk1mn0pqЯ57uvwxy2{|}";
			this.doublestruckList = "!\"#$%&'()*+,-./𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡:;<=>?@𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ[\\]^_`𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫{|}";
            this.thiccList = " !\"#$%&'()*+,-./0123456789:;<=>?@卂乃匚刀乇下厶卄工丁长乚从ん口尸㔿尺丂丅凵リ山乂丫乙[\\]^_`卂乃匚刀乇下厶卄工丁长乚从ん口尸㔿尺丂丅凵リ山乂丫乙{|}";

            this.toolbarString = `<div id="bfredux" class='bf-toolbar'><div class='bf-arrow'></div></div>`;

            this.discordWrappers = {bold: "**", italic: "*", underline: "__", strikethrough: "~~", code: "`", codeblock: "```", spoiler: "||"};

            this.customWrappers = Object.keys(this.defaultSettings.wrappers);
            this.buttonOrder = Object.keys(this.defaultSettings.toolbar);


            this.toolbarData = (() => {return {
    bold: {type: "native-format",
            name: "Bold",
            displayName: "<b>Bold</b>",
            icon: `<img src='data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'>`},
    italic: {type: "native-format",
            name: "Italic",
            displayName: "<i>Italic</i>",
            icon: `<img src='data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z"/></svg>'>`},
    underline: {type: "native-format",
                name: "Underline",
                displayName: "<u>Underline</u>",
                icon: `<img src='data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z"/></svg>'>`},
    strikethrough: {type: "native-format",
                    name: "Strikethrough",
                    displayName: "<s>Strikethrough</s>",
                    icon: `<img src='data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z"/></svg>'>`},
    spoiler: {type: "native-format",
              name: "Spoiler",
              displayName: "Spoiler",
              icon: `<img src='data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="white" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>'>`},
    code: {type: "native-format",
            name: "Code",
            displayName: "<span style='font-family:monospace;'>Code</span>",
            icon: `<img src='data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></svg>'>`},
    codeblock: {type: "native-format",
                name: "Codeblock",
                displayName: "<span style='font-family:monospace;text-decoration: underline overline;'>|Codeblock|</span>",
                icon: `<img src='data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M7.77 6.76L6.23 5.48.82 12l5.41 6.52 1.54-1.28L3.42 12l4.35-5.24zM7 13h2v-2H7v2zm10-2h-2v2h2v-2zm-6 2h2v-2h-2v2zm6.77-7.52l-1.54 1.28L20.58 12l-4.35 5.24 1.54 1.28L23.18 12l-5.41-6.52z"/></svg>'>`},
    superscript: {type: "bfr-format",
                name: "Superscript",
                displayName: "ˢᵘᵖᵉʳˢᶜʳᶦᵖᵗ",
                icon: "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAC9UlEQVR4nO2av08UQRTH+WFhDDFXUFhcYcKBFMRYWtgLgdLS4go7IHAJBYl2FJb8UOsrLC0sjJyGPwMTf5xWJFhYUFBcYfRjsUOczL1d9sfczuwyn+Sa2/fefWdu33ffwI2NBQKBQIUBFoBdoA+cA7+Ad8AO0HStb2QAN4Bt4JR4PgEd4KZrvVYBrgNvExZu8tq1ZqsATzMs/oIt17qtADSJel2nDzxS16aBJ0ReoDMAFlzrLwzwXFh8Q4hrAj+N2F0Xmq0C9IxFPU6IbRuxn8vUOhKAL8ai7iTE3jViT8vU6hzgvrEBZ641lQZwCzgxNuDIta5SIJoOzcUDrLjWNnKU8ZmPSYCdvAW7QrG2XdmiYwN0M+TfJjoDSLwBruUVNgUcGwXPsThUqFvW/NaOgakUuQ2i2WAgLPw3sO1UYIrauTaY6DywBZzFfOsnwIOi+vQPLHSLJtTtCnXbCfEN4BnDU55OD5guqq2w2BT1Mm8q8q2emrxaLz68BRwaNb8BizlqLapcnUOgdUleIfKv/r+AJaIDiM57YCZDjZbK0ekDSyly3W6AErEu1N7PkL8v5K+nzHW/AUrIgVH7L7CWIm9NxeocWBNWFsh+8JUEPwAeqhidS/veW8jgB8AMOfvea5D9YE+I2xPiUvW99zDsB3+AVe36qnpPp3p9HwcJ4ywjHKO9ImGhIz1IeUWMH9Sz7+MQ/KCefR8H8nwAVX7eZyFswFVugSttgsiPwT7Do3L9HoPIg9AAuKde5l9x6jUIxfR9R7veEa7Xww+Q+/4VMKnFTKr3TKrtB8jH4Y/AvBA7r67pVPc4jPy8/0HC/9+AFRWjU835ALnvN1PkbQp51fID5L5/CUykyJ1QsSbV8APkvv8AzGWoMadydPz3A+S+/w4s56i1rHJ1/PYD5L7fKFBvQ6jnpx8g9/0LYLxAzXFVw8QvP0Du+x4wa6H2LMM/ffPHD5D73qrAmA32ww+Q+976LRrTYn76QSAQCAQCgUAgEKg8/wD8huCrKK8/kQAAAABJRU5ErkJggg=='>"},
    smallcaps: {type: "bfr-format",
                name: "Smallcaps",
                displayName: "SᴍᴀʟʟCᴀᴘs",
                icon: `<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><defs><path d="M24 24H0V0h24v24z" id="a"/></defs><clipPath id="b"><use overflow="visible" href="#a"/></clipPath><path clip-path="url(#b)" d="M2.5 4v3h5v12h3V7h5V4h-13zm19 5h-9v3h3v7h3v-7h3V9z"/></svg>`},
    fullwidth: {type: "bfr-format",
                name: "Fullwidth",
                displayName: "Fullwidth",
                icon: "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAA80lEQVR4nO3XzQ2CMBxAcQ4MwcFFHIRBWIQF2MBBZBAGeV5ogkSj1JQife9s0n9/Uj6qyszMzMzMLCIyl3v/AghQOkBsp9lIbAIIIIAAAggggAACCCCAAAIIIIAAuefZPQEEEEAAAQQQQIDTAAA1MGz4fRQAMAB13JSJAhpg3OOfnL1GoEm91lcBLXDf61JeXDR3oE293qdhOmDa8yyvTs4EdKnXfDXEBejX5zgDQKgHLqnXDgNcgdubQXJ2A66pN/903g9Y2vsCpQPMCOUegQVCuTfB1TBlPgZXA5X7IhSi5FfhEBs/hn5Y53gfQ2ZmZv/ZAxEIe1ZZ+BlyAAAAAElFTkSuQmCC'>"},
    upsidedown: {type: "bfr-format",
                name: "Upsidedown",
                displayName: "uʍopǝpᴉsd∩",
                icon: `<img src='data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M16 17.01V10h-2v7.01h-3L15 21l4-3.99h-3zM9 3L5 6.99h3V14h2V6.99h3L9 3z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'>`},
    varied: {type: "bfr-format",
            name: "Varied",
            displayName: "VaRiEd CaPs",
            icon: `<img src='data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M18 4l-4 4h3v7c0 1.1-.9 2-2 2s-2-.9-2-2V8c0-2.21-1.79-4-4-4S5 5.79 5 8v7H2l4 4 4-4H7V8c0-1.1.9-2 2-2s2 .9 2 2v7c0 2.21 1.79 4 4 4s4-1.79 4-4V8h3l-4-4z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'>`},
    leet: {type: "bfr-format",
            name: "Leet",
            displayName: "1337",
            icon: "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABnklEQVRoge2YL1MCQRiHCRf8EATCBZwhEPwARILR4DeQaDDeDIFgMPAhDAQDgaDdYDAQcMYZMThDNBgIBsJj2GXmXFdub937g/M+kfe3w+/ZeQ8YGg1BEITaAbSAa2BF9ayACRDnKb+utrOVNS4SqJuvK1MXgUXVLXfw4iLwDae9K5DcfUQgMCKQev3OnBXIrAiB81KqK86KEDgE3kooPweawQX0zPYl1wNGwDJnyQQ4sswuXfv4CPQsb9hJzbs7ZLal41S+Y2Q2pG4/uICePxuRgSXTtAg0LbmBkZnk7eMj0DciCyAyMolFYGhkIuAxNf8EWoUL6MzUiN0AMermE9QqmGyAoc7E+kyaxLePj0BL31gWc9we7iVwUJqAztnWZMsGONW5CBhnCPT/2sdHIOLnGmzLn1jyV7+UH4fo43VAS4xQq/IB3ALdHflj4F5nH4CLkH38DhSMCJTQMWyf/yDwZB6qEa8uAraPxrowcxGIqe8fW23XvWujfu+8V9sZUB1muJYX9p2sfai6XyZ7IxDi6axUTAREQBAEoQ58Aaheq+k8olaNAAAAAElFTkSuQmCC'>"},
    doublestruck: {type: "bfr-format",
            name: "Double Struck",
            displayName: "1337",
            icon: "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAADCElEQVR4nO3XbYimYxQH8N9j1rDUatAyVq2XJc365u0TH5C8JiJhy6aljQ+bIilkixKySyspEeW1FKH2y2Tbdj+oYWPIa0xeWrLWW8LszhwfzjV5dprnuWfNPN1N3f+6O899nes+5/yv51znOlcrIixkHFB3AHNFQ6BuNATqRkOgbjQE6saiCv3NOKbtPTCBPfgDu/A1RvH3fvgdxLU4q9g/CLvxM77FexgptruiVdFKjGAIv6MfAyXoieL0MLQwjjfwGLZX+FyHB3EwfsVL+FwuznKcjdPL3BvwfFdrEdHtGYmIp8vvCyNxXJu+LyJWRMTa+A8bI6K/g73VZc6fEbE3IoY6zDs+IjZExNUV8c2ZwNSzqOi2lcBenmFOKyK+j4jhiNgUEV9UBTebZ7438ety31yDW6bphmS+P4KfsGQ+HPaiCj2DrbhH7pMpHFXkV9iGpZLsnNCrMvocjsY5bWO7i1yOYTyLp/AJHsal/se/0isC7xTZTmAUP+Km8n4jzse7uA5vygq3GRfP1lGvCOwscrBtbALrcRVul+V3GKuxDCfhNhyOt/GKfVNwRvSKwDgmsXja+JPyDHgIO3CrTCn4Ek/gTKzC5dhU5ahXBI4otnfNoLtLHlbfYSPG5EH2KFaWOS/gAZlmJ3Zz1CsCQ0V+2kG/XW7apbLkbpWrPirTDB4v8V3QzVGvCFxW5OaKeb/gVayR++B+3ItT8Zs8LwY7fq03BI7FWnmoVTZjbdiD+2S5vaSMHSqbxo6YbwIDeE1u4jum6Q5EX8X3k/hBrvoZOAQfdvtgvgi0irwTJ+NKWVXasQwfyNVtmRlLcAL+wgZ8gy3dHFfdB+AUmRJTG/N62bf340hZJc4rui0yn8c62FqJt/AZXizzx7C32F8v2+x1kuRF+KdbcLO5D5w2bWzSvheaMbwv+/qPutjqkxXlCpyrc3kclyTvlm1GV1QR6CUGsEI2eYtl2uzEx/bjdlcngXnBgr/UNwTqRkOgbjQE6kZDoG40BOpGQ6BuNATqRkOgbix4Av8CDzTBCFlkecYAAAAASUVORK5CYII='>"},
    thicc: {type: "bfr-format",
            name: "Extra Thicc",
            displayName: "乇乂下尺卂 下卄工匚匚",
            icon: `<img src='data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIGRpc3BsYXk9Im5vbmUiIGZpbGw9IiNGRkZGRkYiIGQ9Ik0xNS42LDEwLjc5YzAuOTcxLTAuNjcsMS42NS0xLjc3LDEuNjUtMi43OWMwLTIuMjYtMS43NS00LTQtNEg3djE0aDcuMDQNCgljMi4wOSwwLDMuNzEtMS43LDMuNzEtMy43OUMxNy43NSwxMi42ODksMTYuODkxLDExLjM5LDE1LjYsMTAuNzl6IE0xMCw2LjVoM2MwLjgzLDAsMS41LDAuNjcsMS41LDEuNVMxMy44Myw5LjUsMTMsOS41aC0zVjYuNXoNCgkgTTEzLjUsMTUuNUgxMHYtM2gzLjVjMC44MywwLDEuNSwwLjY3LDEuNSwxLjVTMTQuMzMsMTUuNSwxMy41LDE1LjV6Ii8+DQo8cGF0aCBmaWxsPSJub25lIiBkPSJNMCwwaDI0djI0SDBWMHoiLz4NCjx0ZXh0IHRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIDEgNS45MzU1IDE0Ljk5NzEpIiBmaWxsPSIjRkZGRkZGIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgZm9udC1mYW1pbHk9IidLb3pHb1ByNk4tUmVndWxhci04M3B2LVJLU0otSCciIGZvbnQtc2l6ZT0iMTIuNTY0Ij7kuYc8L3RleHQ+DQo8L3N2Zz4NCg=='>`
            },
};})();
            this.allLanguages = (() => {return {
    C: {cpp: "C++", csharp: "C#", coffeescript: "CoffeeScript", css: "CSS"},
    H: {html: "HTML/XML"},
    J: {java: "Java", js: "JavaScript", json: "JSON"},
    M: {markdown: "Markdown"},
    P: {perl: "Perl", php: "PHP", py: "Python"},
    R: {ruby: "Ruby"},
    S: {sql: "SQL"},
    V: {vbnet: "VB.NET", vhdl: "VHDL"}
};})();
            this.mainCSS = `.bf-toolbar {
	user-select: none;
	white-space: nowrap;
	font-size:85%;
	display:block;
	position: absolute;
	color: rgba(255, 255, 255, .5);
	width:auto!important;
	right:0;
	bottom:auto;
	border-radius:3px;
	height:27px!important;
	top:0px;
	transform:translate(0,-100%);
	opacity:1;
	overflow: hidden!important;
	pointer-events: none;
	padding:10px 30px 15px 5px;
	margin: 0 5px 0 0;
}

.bf-toolbar.bf-visible,
.bf-toolbar.bf-hover:hover{
	pointer-events: initial;
}

.bf-toolbar::before {
	content:"";
	display: block;
	width:100%;
	height:calc(100% - 15px);
	position: absolute;
	z-index: -1;
	background:#424549;
	pointer-events: initial;
	left:0px;
	top:5px;
	border-radius:3px;
	transform:translate(0,55px);
	transition:all 200ms ease;
}

.theme-light .bf-toolbar::before {
	background: #97A0AA;
}

.bf-toolbar.bf-visible:before,
.bf-toolbar.bf-hover:hover:before {
	transform:translate(0,0px);
	transition:all 200ms cubic-bezier(0,0,0,1);
}

.bf-toolbar .format {
	display: inline;
	padding: 7px 5px;
	cursor: pointer;
	display : inline-flex;
	align-items : center;
	transform:translate(0,55px);
	transition:all 50ms,transform 200ms ease;
	position:relative;
	pointer-events: initial;
	border-radius:2px;
	max-height: 27px;
	box-sizing: border-box;
	vertical-align: middle;
}

.bf-toolbar .format > img,
.bf-toolbar .format > svg {
	opacity: 0.6;
	vertical-align: middle;
	max-height: inherit;
}

.bf-toolbar .format .format-border {
	border: 1px solid rgba(255, 255, 255, .5);
	border-radius: inherit;
}

.bf-toolbar .format:hover{
	background:rgba(255,255,255,.1);
	color:rgba(255,255,255,.9);
}

.bf-toolbar .format:active{
	background:rgba(0,0,0,.1)!important;
	transition:all 0ms,transform 200ms ease;
}

.bf-toolbar.bf-visible .format,
.bf-toolbar.bf-hover:hover .format{
	transform:translate(0,0);
	transition:all 50ms,transform 200ms cubic-bezier(0,0,0,1);
}

.bf-toolbar .format.disabled {
	display: none;
}

.bf-toolbar .format.ghost {
	color: transparent;
	background: rgba(0,0,0,.1);
}

.bf-toolbar .format.ghost > img,
.bf-toolbar .format.ghost > svg {
	opacity: 0;
}

.theme-light .bf-toolbar:hover .bf-arrow,
.bf-toolbar .bf-arrow {
	content:"";
	display:block;
	background: url('data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
	height:30px;
	width:30px;
	right:5px;
	position: absolute;
	pointer-events: initial;
	bottom:0;
	background-repeat: no-repeat;
	background-position: 50%;
	transition:all 200ms ease;
	opacity: .3;
	cursor:pointer;
}
.theme-light .bf-toolbar .bf-arrow {
	background: url('data:image/svg+xml;utf8,<svg fill="rgb(127,129,134)" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
}
.bf-toolbar.bf-visible .bf-arrow,
.bf-toolbar.bf-hover:hover .bf-arrow {
	transform:translate(0,-14px)rotate(-90deg);
	transition:all 200ms cubic-bezier(0,0,0,1);
	opacity: .9;
}

.message-group .bf-toolbar{
	padding: 10px 5px 15px 5px;
	animation:slide-up 300ms cubic-bezier(0,0,0,1), opacity 300ms ease
}
.upload-modal .bf-toolbar {
	position: relative;
	transform: none;
	padding: 5px 0;
	margin-right: 0;
	border-radius: 2px;
	text-align: center;
	background: #424549;
}
.upload-modal .bf-toolbar::before {
	display: none;
}
.upload-modal .bf-toolbar .format:hover{
	background:rgba(255,255,255,.1);
}
.upload-modal .bf-toolbar .format:active{
	background:rgba(0,0,0,.1);
}
.upload-modal .bf-toolbar .format,
.upload-modal .bf-toolbar:before,
.message-group .bf-toolbar .format,
.message-group .bf-toolbar:before{
	transform:translate(0,0);
}
.upload-modal .bf-toolbar .bf-arrow,
.message-group .bf-toolbar .bf-arrow{
	display: none;
}

.bf-toolbar.bf-left {
	left: 0!important;
	right: auto!important;
	margin-right: 0!important;
	margin-left: 5px!important;
	padding: 10px 10px 15px 30px!important;
}

.bf-toolbar.bf-left .bf-arrow {
	left: 5px!important;
	right: auto!important;
}

.bf-toolbar.bf-left.bf-hover:hover .bf-arrow,.bf-toolbar.bf-left.bf-visible .bf-arrow {
	-webkit-transform: translate(0,-14px) rotate(90deg)!important;
	-ms-transform: translate(0,-14px) rotate(90deg)!important;
	transform: translate(0,-14px) rotate(90deg)!important;
}
.bf-languages {
	display: block;
	position: fixed !important;
	transform: scale(1,0);
	transform-origin: 100% 100%!important;
	background: #424549;
	border-radius: 3px;
	color: rgba(255,255,255,.5);
	padding: 3px;
}
.bf-languages.bf-visible {
	height: auto;
	transition: 200ms cubic-bezier(.2,0,0,1);
	transform: scale(1,1);
	transform-origin: 100% 100%!important;
}

.bf-languages div {
	display: block;
	cursor: pointer;
	padding: 5px 7px;
	border-radius: 2px;
}

.bf-languages div:hover {
	background: rgba(255,255,255,.1);
	color: rgba(255,255,255,.9);
}`;
        }

        async onStart() {
            // await PluginUtilities.addScript("sortableScript", "//rauenzi.github.io/BetterDiscordAddons/Plugins/Sortable.js");
            DOM.addStyle(this.name + "-style", this.mainCSS);
            this.buttonOrder = PluginUtilities.loadData(this.name, "buttonOrder", this.buttonOrder);
            this.setupToolbar();
            Patcher.before(this.name, DiscordModules.MessageActions, "sendMessage", (_, [, msg]) => {
                msg.content = this.format(msg.content);
            });
        }

        onStop() {
            Patcher.unpatchAll(this.name);
            // $("*").off("." + this.name);
            document.querySelector(".bf-toolbar")?.remove();
            // PluginUtilities.removeScript("sortableScript");
            DOM.removeStyle(this.name + "-style");
        }

        observer(e) {
            if (!e.addedNodes.length || !(e.addedNodes[0] instanceof Element)) return;

            const elem = e.addedNodes[0];
            const textarea = elem.matches(DiscordSelectors.Textarea.textArea) ? elem : elem.querySelector(DiscordSelectors.Textarea.textArea);
            if (textarea) this.addToolbar(textarea);
        }

        updateStyle() {
            this.updateSide();
            this.updateOpacity();
            this.updateFontSize();
        }

        updateSide() {
            const toolbar = document.querySelector(".bf-toolbar");
            if (!toolbar) return;
            if (this.settings.style.rightSide) toolbar.classList.remove("bf-left");
            else toolbar.classList.add("bf-left");
        }

        updateOpacity() {
            const toolbar = document.querySelector(".bf-toolbar");
            if (!toolbar) return;
            toolbar.style.opacity = this.settings.style.toolbarOpacity;
        }

        updateFontSize() {
            const toolbar = document.querySelector(".bf-toolbar");
            if (!toolbar) return;
            toolbar.style.fontSize = this.settings.style.fontSize + "%";
        }

        openClose() {
            this.isOpen = !this.isOpen;
            const toolbar = document.querySelector(".bf-toolbar");
            if (!toolbar) return;
            toolbar.classList.toggle("bf-visible");
        }

        escape(s) {
            return s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
        }

        doFormat(text, wrapper, offset) {

            // If this is not a wrapper, return original
            if (text.substring(offset, offset + wrapper.length) != wrapper) return text;

            let returnText = text;
            const len = text.length;
            const begin = text.indexOf(wrapper, offset);

            if (text[begin - 1] == "\\") return text; // If the wrapper is escaped, remove the backslash and return the text

            let end = text.indexOf(wrapper, begin + wrapper.length);
            if (end != -1) end += wrapper.length - 1;

            // Making it to this point means that we have found a full wrapper
            // This block performs inner chaining
            if (this.settings.plugin.chainFormats) {
                for (let w = 0; w < this.customWrappers.length; w++) {
                    const newText = this.doFormat(returnText, this.settings.wrappers[this.customWrappers[w]], begin + wrapper.length);
                    if (returnText != newText) {
                        returnText = newText;
                        end = end - this.settings.wrappers[this.customWrappers[w]].length * 2;
                    }
                }
            }

            returnText = returnText.replace(new RegExp(`([^]{${begin}})${this.escape(wrapper)}([^]*)${this.escape(wrapper)}([^]{${len - end - 1}})`), (match, before, middle, after) => {
                let letterNum = 0;
                middle = middle.replace(/./g, letter => {
                    const index = this.replaceList.indexOf(letter);
                    letterNum += 1;
                    if (wrapper == this.settings.wrappers.fullwidth) {
                        if (this.settings.formatting.fullWidthMap) return index != -1 ? this.fullwidthList[index] : letter;
                        return index != -1 ? letterNum == middle.length ? letter.toUpperCase() : letter.toUpperCase() + " " : letter;
                    }
                    else if (wrapper == this.settings.wrappers.superscript) {return index != -1 ? this.superscriptList[index] : letter;}
                    else if (wrapper == this.settings.wrappers.smallcaps) {return index != -1 ? this.smallCapsList[index] : letter;}
                    else if (wrapper == this.settings.wrappers.upsidedown) {return index != -1 ? this.upsideDownList[index] : letter;}
                    else if (wrapper == this.settings.wrappers.leet) {return index != -1 ? this.leetList[index] : letter;}
                    else if (wrapper == this.settings.wrappers.thicc) {return index != -1 ? this.thiccList[index] : letter;}
                    else if (wrapper == this.settings.wrappers.doublestruck) {return index != -1 ? this.doublestruckList[index] : letter;}
                    else if (wrapper == this.settings.wrappers.varied) {
                        const compare = this.settings.formatting.startCaps ? 1 : 0;
                        if (letter.toLowerCase() == letter.toUpperCase()) letterNum = letterNum - 1;
                        return index != -1 ? letterNum % 2 == compare ? letter.toUpperCase() : letter.toLowerCase() : letter;
                    }
                    return letter;
                });
                if (wrapper == this.settings.wrappers.upsidedown && this.settings.formatting.reorderUpsidedown) return before + middle.split("").reverse().join("") + after;
                return before + middle + after;
            });

            return returnText;
        }

        format(string) {
            let text = string;
            for (let i = 0; i < text.length; i++) {
                if (text[i] == "`") {
                    const next = text.indexOf("`", i + 1);
                    if (next != -1) i = next;
                }
                else if (text[i] == "@") {
                    const match = /@.*#[0-9]*/.exec(text.substring(i));
                    if (match && match.index == 0) i += match[0].length - 1;
                }
                else {
                    for (let w = 0; w < this.customWrappers.length; w++) {
                        if (!this.settings.formats[this.customWrappers[w]]) continue;
                        const newText = this.doFormat(text, this.settings.wrappers[this.customWrappers[w]], i);
                        if (text != newText) {
                            text = newText;
                            i = i - this.settings.wrappers[this.customWrappers[w]].length * 2;
                        }
                    }
                }
            }
            if (this.settings.plugin.closeOnSend) document.querySelector(".bf-toolbar")?.classList.remove("bf-visible");
            return text;
        }

        async wrapSelection(leftWrapper, rightWrapper) {
            if (!rightWrapper) rightWrapper = leftWrapper;
            if (leftWrapper.startsWith("```")) leftWrapper = leftWrapper + "\n";
            if (rightWrapper.startsWith("```")) rightWrapper = "\n" + rightWrapper;
            const textarea = document.querySelector(DiscordSelectors.Textarea.textArea);
            if (!textarea) return;
            if (textarea.tagName === "TEXTAREA") return this.oldWrapSelection(textarea, leftWrapper, rightWrapper);
            const slateNode = ReactTools.getOwnerInstance(textarea);
            const slate = slateNode?.ref?.current?.getSlateEditor();
            if (!slate) return; // bail out if no slate

            const currentSelection = Utilities.deepclone(slate.selection);
            slate.apply({type: "insert_text", text: leftWrapper, path: slate.selection.anchor.path, offset: slate.selection.anchor.offset});
            slate.apply({type: "insert_text", text: rightWrapper, path: slate.selection.focus.path, offset: slate.selection.focus.offset});

            currentSelection.anchor.offset += leftWrapper.length;
            currentSelection.focus.offset += rightWrapper.length;
            slateNode.focus();
        }

        oldWrapSelection(textarea, leftWrapper, rightWrapper) {
            let text = textarea.value;
            const start = textarea.selectionStart;
            const len = text.substring(textarea.selectionStart, textarea.selectionEnd).length;
            text = leftWrapper + text.substring(textarea.selectionStart, textarea.selectionEnd) + rightWrapper;
            textarea.focus();
            document.execCommand("insertText", false, text);
            textarea.selectionStart = start + leftWrapper.length;
            textarea.selectionEnd = textarea.selectionStart + len;
        }

        getContextMenu() {
            return ContextMenu.buildMenu(
                Object.keys(this.allLanguages).map(letter => {
                    return {
                        type: "submenu",
                        label: letter,
                        items: Object.keys(this.allLanguages[letter]).map(language => {
                            return {label: this.allLanguages[letter][language], action: () => {this.wrapSelection("```" + language + "\n", "```");}};
                        })
                    };
                })
            );
        }

        buildToolbar() {
            const toolbar = DOM.parseHTML(this.toolbarString);
            const sorted = Object.keys(this.settings.toolbar).sort((a,b) => {return this.buttonOrder.indexOf(a) - this.buttonOrder.indexOf(b);});
            for (let i = 0; i < sorted.length; i++) {
                const button = DOM.parseHTML("<div class='format'>");
                if (!this.toolbarData[sorted[i]]) continue;
                button.classList.add(this.toolbarData[sorted[i]].type);
                UI.createTooltip(button, this.toolbarData[sorted[i]].name);
                if (!this.settings.toolbar[sorted[i]]) button.classList.add("disabled");
                if (sorted[i] === "codeblock") {
                    const contextMenu = this.getContextMenu();
                    button.addEventListener("contextmenu", (e) => {
                        ContextMenu.open(e, contextMenu, {align: "bottom"});
                    });
                }
                button.dataset.name = sorted[i];
                if (this.settings.style.icons) button.innerHTML = this.toolbarData[sorted[i]].icon;
                else button.innerHTML = this.toolbarData[sorted[i]].displayName;
                toolbar.append(button);
            }
            // window.Sortable.create(toolbar, {
            //     draggable: ".format", // css-selector of elements, which can be sorted
            //     ghostClass: "ghost",
            //     onUpdate: () => {
            //         const buttons = toolbar.querySelectorAll(".format");
            //         for (let i = 0; i < buttons.length; i++) {
            //             this.buttonOrder[i] = buttons[i].dataset.name;
            //         }
            //         PluginUtilities.saveData(this.name, "buttonOrder", this.buttonOrder);
            //     }
            // });
            if (!this.settings.style.icons) {
                toolbar.addEventListener("mousemove", (e) => {
                    const target = e.currentTarget;
                    const pos = e.pageX - target.parentElement.getBoundingClientRect().left;
                    const width = parseInt(getComputedStyle(target).width);
                    let diff = -1 * width;
                    Array.from(target.children).forEach(elem => {
                        diff += elem.offsetWidth;
                    });
                    target.scrollLeft = (pos / width * diff);
                });
            }

            return toolbar;
        }

        setupToolbar() {
            document.querySelector(".bf-toolbar")?.remove();
            document.querySelectorAll(`${DiscordSelectors.Textarea.textArea}`).forEach(elem => {
                this.addToolbar(elem.children[0]);
            });
        }

        addToolbar(textarea) {
            const toolbarElement = this.buildToolbar();
            if (this.settings.plugin.hoverOpen == true) toolbarElement.classList.add("bf-hover");
            if (this.isOpen) toolbarElement.classList.add("bf-visible");

            const inner = textarea.parentElement.parentElement;
            inner.parentElement.insertBefore(toolbarElement, inner.nextSibling);

            toolbarElement.addEventListener("click", e => {
                    e.preventDefault();
                    e.stopPropagation();
                    const button = e.target.closest("div");
                    if (button.classList.contains("bf-arrow")) {
                        if (!this.settings.plugin.hoverOpen) this.openClose();
                    }
                    else if (button.classList.contains("format")) {
                        let wrapper = "";
                        if (button.classList.contains("native-format")) wrapper = this.discordWrappers[button.dataset.name];
                        else wrapper = this.settings.wrappers[button.dataset.name];
                        this.wrapSelection(wrapper);
                    }
                });

            // textarea.parent().parent().after(toolbarElement)
            //     .siblings(".bf-toolbar")
            //     .off("click." + this.name)
            //     .on("click." + this.name, "div", e => {
            //         e.preventDefault();
            //         e.stopPropagation();
            //         const button = e.currentTarget;
            //         if (button.classList.contains("bf-arrow")) {
            //             if (!this.settings.plugin.hoverOpen) this.openClose();
            //         }
            //         else {
            //             let wrapper = "";
            //             if (button.classList.contains("native-format")) wrapper = this.discordWrappers[button.data("name")];
            //             else wrapper = this.settings.wrappers[button.data("name")];
            //             this.wrapSelection(wrapper);
            //         }
            //     });
            this.updateStyle();
        }

        getSettingsPanel() {
            const panel = this.buildSettingsPanel();
            panel.addListener(this.updateSettings.bind(this));
            return panel.getElement();
        }

        updateSettings(group, id, value) {

            if (group == "toolbar") this.setupToolbar();
            if (group == "plugin" && id == "hoverOpen") {
                const toolbar = document.querySelector(".bf-toolbar");
                if (value) {
                    toolbar?.classList.remove("bf-visible");
                    toolbar?.classList.add("bf-hover");
                }
                else {
                    toolbar?.classList.remove("bf-hover");
                }
            }

            if (group == "style") {
                if (id == "icons") this.setupToolbar();
                if (id == "rightSide") this.updateSide();
                if (id == "toolbarOpacity") this.updateOpacity();
                if (id == "fontSize") this.updateFontSize();
            }

            // let resetButton = $("<button>");
            // resetButton.on("click", () => {
            //     this.settings = this.defaultSettings;
            //     this.saveSettings();
            //     this.setupToolbar();
            //     panel.empty();
            //     this.generateSettings(panel);
            // });
            // resetButton.text("Reset To Defaults");
            // resetButton.css("float", "right");
            // resetButton.attr("type","button");

            // panel.append(resetButton);
        }

    };
};
     return plugin(Plugin, Api);
})(global.ZeresPluginLibrary.buildPlugin(config));
/*@end@*/

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions