Furaffinity-Message-Box

Library to hold MessageBox functions for Furaffinity

이 스크립트는 직접 설치하는 용도가 아닙니다. 다른 스크립트에서 메타 지시문 // @require https://update.greasyfork.org/scripts/528997/1765109/Furaffinity-Message-Box.js을(를) 사용하여 포함하는 라이브러리입니다.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name        Furaffinity-Message-Box
// @namespace   Violentmonkey Scripts
// @require     https://greasyfork.org/scripts/525666-furaffinity-prototype-extensions/code/525666-furaffinity-prototype-extensions.js
// @grant       GM_info
// @version     1.0.5
// @author      Midori Dragon
// @description Library to hold MessageBox functions for Furaffinity
// @icon        https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png
// @license     MIT
// @homepageURL https://greasyfork.org/scripts/528997-furaffinity-message-box
// @supportURL  https://greasyfork.org/scripts/528997-furaffinity-message-box/feedback
// ==/UserScript==
// jshint esversion: 11
(function () {
    'use strict';

    /**
     * Specifies the buttons that are displayed on a message box.
     * Similar to System.Windows.Forms.MessageBoxButtons in C#.
     */
    var MessageBoxButtons;
    (function (MessageBoxButtons) {
        /**
         * The message box contains an OK button.
         */
        MessageBoxButtons[MessageBoxButtons["OK"] = 0] = "OK";
        /**
         * The message box contains OK and Cancel buttons.
         */
        MessageBoxButtons[MessageBoxButtons["OKCancel"] = 1] = "OKCancel";
        /**
         * The message box contains Abort, Retry, and Ignore buttons.
         */
        MessageBoxButtons[MessageBoxButtons["AbortRetryIgnore"] = 2] = "AbortRetryIgnore";
        /**
         * The message box contains Yes, No, and Cancel buttons.
         */
        MessageBoxButtons[MessageBoxButtons["YesNoCancel"] = 3] = "YesNoCancel";
        /**
         * The message box contains Yes and No buttons.
         */
        MessageBoxButtons[MessageBoxButtons["YesNo"] = 4] = "YesNo";
        /**
         * The message box contains Retry and Cancel buttons.
         */
        MessageBoxButtons[MessageBoxButtons["RetryCancel"] = 5] = "RetryCancel";
    })(MessageBoxButtons || (MessageBoxButtons = {}));

    /**
     * Specifies the icon that is displayed on a message box.
     * Similar to System.Windows.Forms.MessageBoxIcon in C#.
     */
    var MessageBoxIcon;
    (function (MessageBoxIcon) {
        /**
         * No icon is displayed.
         */
        MessageBoxIcon[MessageBoxIcon["None"] = 0] = "None";
        /**
         * An error icon is displayed on the message box.
         */
        MessageBoxIcon[MessageBoxIcon["Error"] = 16] = "Error";
        /**
         * A warning icon is displayed on the message box.
         */
        MessageBoxIcon[MessageBoxIcon["Warning"] = 48] = "Warning";
        /**
         * An information icon is displayed on the message box.
         */
        MessageBoxIcon[MessageBoxIcon["Information"] = 64] = "Information";
        /**
         * A question mark icon is displayed on the message box.
         */
        MessageBoxIcon[MessageBoxIcon["Question"] = 32] = "Question";
    })(MessageBoxIcon || (MessageBoxIcon = {}));

    /**
     * Specifies identifiers to indicate the return value of a dialog box.
     * Similar to System.Windows.Forms.DialogResult in C#.
     */
    var DialogResult;
    (function (DialogResult) {
        /**
         * Nothing is returned from the dialog box. This means that the modal dialog continues running.
         */
        DialogResult[DialogResult["None"] = 0] = "None";
        /**
         * The dialog box return value is OK (usually sent from a button labeled OK).
         */
        DialogResult[DialogResult["OK"] = 1] = "OK";
        /**
         * The dialog box return value is Cancel (usually sent from a button labeled Cancel).
         */
        DialogResult[DialogResult["Cancel"] = 2] = "Cancel";
        /**
         * The dialog box return value is Abort (usually sent from a button labeled Abort).
         */
        DialogResult[DialogResult["Abort"] = 3] = "Abort";
        /**
         * The dialog box return value is Retry (usually sent from a button labeled Retry).
         */
        DialogResult[DialogResult["Retry"] = 4] = "Retry";
        /**
         * The dialog box return value is Ignore (usually sent from a button labeled Ignore).
         */
        DialogResult[DialogResult["Ignore"] = 5] = "Ignore";
        /**
         * The dialog box return value is Yes (usually sent from a button labeled Yes).
         */
        DialogResult[DialogResult["Yes"] = 6] = "Yes";
        /**
         * The dialog box return value is No (usually sent from a button labeled No).
         */
        DialogResult[DialogResult["No"] = 7] = "No";
    })(DialogResult || (DialogResult = {}));

    /**
     * Provides SVG icons for the MessageBox component.
     */
    class MessageBoxIcons {
        /**
         * Gets the SVG icon based on the specified MessageBoxIcon.
         * @param icon The MessageBoxIcon to get the SVG for.
         * @returns The SVG string for the specified icon.
         */
        static getIconSvg(icon) {
            switch (icon) {
                case MessageBoxIcon.Error:
                    return '<svg xmlns="http://www.w3.org/2000/svg" height="32px" viewBox="0 -960 960 960" width="32px" fill="#ff0000"><path d="M480-280q17 0 28.5-11.5T520-320q0-17-11.5-28.5T480-360q-17 0-28.5 11.5T440-320q0 17 11.5 28.5T480-280Zm-40-160h80v-240h-80v240Zm40 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>';
                case MessageBoxIcon.Warning:
                    return '<svg xmlns="http://www.w3.org/2000/svg" height="32px" viewBox="0 -960 960 960" width="32px" fill="#ffcc4d"><path d="m40-120 440-760 440 760H40Zm138-80h604L480-720 178-200Zm302-40q17 0 28.5-11.5T520-280q0-17-11.5-28.5T480-320q-17 0-28.5 11.5T440-280q0 17 11.5 28.5T480-240Zm-40-120h80v-200h-80v200Zm40-100Z"/></svg>';
                case MessageBoxIcon.Information:
                    return '<svg xmlns="http://www.w3.org/2000/svg" height="32px" viewBox="0 -960 960 960" width="32px" fill="#2196f3"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>';
                case MessageBoxIcon.Question:
                    return '<svg xmlns="http://www.w3.org/2000/svg" height="32px" viewBox="0 -960 960 960" width="32px" fill="#2196f3"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>';
                case MessageBoxIcon.None:
                default:
                    return '';
            }
        }
    }

    /**
     * Specifies the theme that is used for the message box.
     */
    var MessageBoxThemes;
    (function (MessageBoxThemes) {
        /**
         * Dark theme with white text and dark gray buttons.
         */
        MessageBoxThemes["Dark"] = "dark";
        /**
         * Aurora theme with white text and medium gray buttons.
         */
        MessageBoxThemes["Aurora"] = "aurora";
        /**
         * Retro theme with white text and medium blue-gray buttons.
         */
        MessageBoxThemes["Retro"] = "retro";
        /**
         * Slate theme with white text and light gray buttons.
         */
        MessageBoxThemes["Slate"] = "slate";
        /**
         * Light theme with black text and light gray buttons.
         */
        MessageBoxThemes["Light"] = "light";
    })(MessageBoxThemes || (MessageBoxThemes = {}));

    function styleInject(css, ref) {
      if ( ref === void 0 ) ref = {};
      var insertAt = ref.insertAt;

      if (typeof document === 'undefined') { return; }

      var head = document.head || document.getElementsByTagName('head')[0];
      var style = document.createElement('style');
      style.type = 'text/css';

      if (insertAt === 'top') {
        if (head.firstChild) {
          head.insertBefore(style, head.firstChild);
        } else {
          head.appendChild(style);
        }
      } else {
        head.appendChild(style);
      }

      if (style.styleSheet) {
        style.styleSheet.cssText = css;
      } else {
        style.appendChild(document.createTextNode(css));
      }
    }

    var css_248z = "/* Base styles */\n.message-box-overlay {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    background-color: rgba(0, 0, 0, 0.5);\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    z-index: 99999999;\n}\n\n/* Dark theme (default) */\n.message-box-container {\n    border: 1px solid #444;\n    border-radius: 5px;\n    padding: 20px;\n    max-width: 500px;\n    width: 100%;\n    font-family: Arial, sans-serif;\n    transition: background-color 0.3s, color 0.3s, border-color 0.3s, box-shadow 0.3s;\n}\n\n.message-box-header {\n    display: flex;\n    align-items: center;\n    margin-bottom: 15px;\n}\n\n.message-box-icon-container {\n    margin-right: 15px;\n    width: 32px;\n    height: 32px;\n    flex-shrink: 0;\n}\n\n.message-box-title {\n    font-size: 18px;\n    font-weight: bold;\n    margin: 0;\n    transition: color 0.3s;\n}\n\n.message-box-content {\n    margin-bottom: 20px;\n    line-height: 1.5;\n    transition: color 0.3s;\n}\n\n.message-box-button-container {\n    display: flex;\n    justify-content: flex-end;\n    gap: 10px;\n}\n\n.message-box-button {\n    padding: 8px 16px;\n    border: none;\n    border-radius: 4px;\n    cursor: pointer;\n    font-size: 14px;\n    font-weight: bold;\n    background-color: #f1efeb;\n    transition: background-color 0.2s, color 0.2s, border-color 0.2s;\n}\n\n.message-box-button:hover {\n    background-color: #e0ded8;\n}\n\n/* Theme: Dark */\nbody[class*=\"theme-dark\"] .message-box-container {\n    background-color: #353b45;\n    border-color: #444;\n    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);\n}\n\nbody[class*=\"theme-dark\"] .message-box-button {\n    background-color: #434b5b;\n}\n\nbody[class*=\"theme-dark\"] .message-box-button:hover {\n    background-color: #576175;\n}\n\n/* Theme: Aurora */\nbody[class*=\"theme-aurora\"] .message-box-container {\n    background-color: #262931;\n    border-color: #444;\n    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);\n}\n\nbody[class*=\"theme-aurora\"] .message-box-button {\n    background-color: #65707c;\n}\n\nbody[class*=\"theme-aurora\"] .message-box-button:hover {\n    background-color: #8692a0;\n}\n\n/* Theme: Retro */\nbody[class*=\"theme-retro\"] .message-box-container {\n    background-color: #2e3b41;\n    border-color: #444;\n    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);\n}\n\nbody[class*=\"theme-retro\"] .message-box-button {\n    background-color: #4c585e;\n}\n\nbody[class*=\"theme-retro\"] .message-box-button:hover {\n    background-color: #7b909a;\n}\n\n/* Theme: Slate */\nbody[class*=\"theme-slate\"] .message-box-container {\n    background-color: #202225;\n    border-color: #444;\n    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);\n}\n\nbody[class*=\"theme-slate\"] .message-box-button {\n    background-color: #8c8c8c;\n}\n\nbody[class*=\"theme-slate\"] .message-box-button:hover {\n    background-color: #b3b1b1;\n}\n\n/* Theme: Light - already defined in base styles */\nbody[class*=\"theme-light\"] .message-box-container {\n    background-color: #f7f7f7;\n    border-color: #ccc;\n    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);\n}\n\nbody[class*=\"theme-light\"] .message-box-button {\n    background-color: #f1efeb;\n}\n\nbody[class*=\"theme-light\"] .message-box-button:hover {\n    background-color: #f1ede7;\n}";
    styleInject(css_248z);

    class string {
        static isNullOrWhitespace(str) {
            return str == null || str.trim() === '';
        }
        static isNullOrEmpty(str) {
            return str == null || str === '';
        }
    }

    class MessageBox {
        static overlay = null;
        static container = null;
        static result = DialogResult.None;
        static resolvePromise = null;
        static currentTheme = MessageBoxThemes.Light;
        /**
         * Gets the current theme.
         * @returns The current theme.
         */
        static getTheme() {
            return this.currentTheme;
        }
        /**
         * Shows a message box with the specified text, caption, buttons, and icon.
         * @param text The text to display in the message box.
         * @param caption The text to display in the title bar of the message box.
         * @param buttons One of the MessageBoxButtons values that specifies which buttons to display in the message box.
         * @param icon One of the MessageBoxIcon values that specifies which icon to display in the message box.
         * @returns A DialogResult value that indicates which button was clicked.
         */
        static async show(text, caption = '', buttons = MessageBoxButtons.OK, icon = MessageBoxIcon.None) {
            // Create a promise that will be resolved when a button is clicked
            return new Promise((resolve) => {
                this.resolvePromise = resolve;
                try {
                    this.createMessageBox(text, caption, buttons, icon);
                }
                catch (error) {
                    const reason = error instanceof Error ? error.message : String(error);
                    const fallback = this.getFallbackResult(buttons);

                    alert(`MessageBox failed to display (${reason})\n\n[${caption}]\n${text}`);
                    this.resolvePromise = null;
                    resolve(fallback);
                }
            });
        }
        /**
         * Returns the strongest negating DialogResult for the given button set,
         * used as a fallback when the message box cannot be shown.
         */
        static getFallbackResult(buttons) {
            switch (buttons) {
                case MessageBoxButtons.OK:
                    return DialogResult.OK;
                case MessageBoxButtons.OKCancel:
                    return DialogResult.Cancel;
                case MessageBoxButtons.AbortRetryIgnore:
                    return DialogResult.Abort;
                case MessageBoxButtons.YesNoCancel:
                    return DialogResult.Cancel;
                case MessageBoxButtons.YesNo:
                    return DialogResult.No;
                case MessageBoxButtons.RetryCancel:
                    return DialogResult.Cancel;
                default:
                    return DialogResult.Cancel;
            }
        }
        /**
         * Creates the message box elements and adds them to the DOM.
         */
        static createMessageBox(text, caption, buttons, icon) {
            // Create overlay
            this.overlay = document.createElement('div');
            this.overlay.className = 'message-box-overlay';
            // Create container
            this.container = document.createElement('div');
            this.container.className = 'message-box-container';
            // Create header (icon + title)
            const header = document.createElement('div');
            header.className = 'message-box-header';
            // Add icon if specified
            if (icon !== MessageBoxIcon.None) {
                const iconContainer = document.createElement('div');
                iconContainer.className = 'message-box-icon-container';
                iconContainer.innerHTML = MessageBoxIcons.getIconSvg(icon);
                header.appendChild(iconContainer);
            }
            // Add title if specified
            if (!string.isNullOrWhitespace(caption)) {
                const title = document.createElement('h3');
                title.className = 'message-box-title';
                title.textContent = caption;
                header.appendChild(title);
            }
            // Add header to container if it has children
            if (header.children.length !== 0) {
                this.container.appendChild(header);
            }
            // Add content
            const content = document.createElement('div');
            content.className = 'message-box-content';
            content.textContent = text;
            this.container.appendChild(content);
            // Add buttons
            const buttonContainer = document.createElement('div');
            buttonContainer.className = 'message-box-button-container';
            // Add appropriate buttons based on the MessageBoxButtons enum
            this.addButtons(buttonContainer, buttons);
            this.container.appendChild(buttonContainer);
            this.overlay.appendChild(this.container);
            // Add to DOM
            document.body.appendChild(this.overlay);
        }
        /**
         * Adds the appropriate buttons to the message box based on the MessageBoxButtons enum.
         */
        static addButtons(buttonContainer, buttons) {
            switch (buttons) {
                case MessageBoxButtons.OK:
                    this.createButton(buttonContainer, 'OK', DialogResult.OK);
                    break;
                case MessageBoxButtons.OKCancel:
                    this.createButton(buttonContainer, 'OK', DialogResult.OK);
                    this.createButton(buttonContainer, 'Cancel', DialogResult.Cancel);
                    break;
                case MessageBoxButtons.AbortRetryIgnore:
                    this.createButton(buttonContainer, 'Abort', DialogResult.Abort);
                    this.createButton(buttonContainer, 'Retry', DialogResult.Retry);
                    this.createButton(buttonContainer, 'Ignore', DialogResult.Ignore);
                    break;
                case MessageBoxButtons.YesNoCancel:
                    this.createButton(buttonContainer, 'Yes', DialogResult.Yes);
                    this.createButton(buttonContainer, 'No', DialogResult.No);
                    this.createButton(buttonContainer, 'Cancel', DialogResult.Cancel);
                    break;
                case MessageBoxButtons.YesNo:
                    this.createButton(buttonContainer, 'Yes', DialogResult.Yes);
                    this.createButton(buttonContainer, 'No', DialogResult.No);
                    break;
                case MessageBoxButtons.RetryCancel:
                    this.createButton(buttonContainer, 'Retry', DialogResult.Retry);
                    this.createButton(buttonContainer, 'Cancel', DialogResult.Cancel);
                    break;
            }
        }
        /**
         * Creates a button element with the specified text and result.
         */
        static createButton(container, text, result) {
            const button = document.createElement('button');
            button.className = 'message-box-button';
            button.textContent = text;
            // Add click handler
            button.addEventListener('click', () => {
                this.close(result);
            });
            container.appendChild(button);
        }
        /**
         * Closes the message box and resolves the promise with the specified result.
         */
        static close(result) {
            this.result = result;
            // Remove from DOM
            if (this.overlay != null) {
                document.body.removeChild(this.overlay);
                this.overlay = null;
                this.container = null;
            }
            // Resolve the promise
            if (this.resolvePromise != null) {
                this.resolvePromise(result);
                this.resolvePromise = null;
            }
        }
    }

    Object.defineProperties(window, {
        FAMessageBox: { get: () => MessageBox },
        FAMessageBoxButtons: { get: () => MessageBoxButtons },
        FAMessageBoxIcon: { get: () => MessageBoxIcon },
        FADialogResult: { get: () => DialogResult },
    });
    let themeClassName = 'dark';
    const themeStylesheets = document.head.querySelectorAll('link[rel="stylesheet"][href]') ?? [];
    for (const themeStylesheet of Array.from(themeStylesheets)) {
        const themePath = themeStylesheet.getAttribute('href')?.toLowerCase() ?? '';
        if (themePath.includes('dark')) {
            themeClassName = 'dark';
        }
        else if (themePath.includes('aurora')) {
            themeClassName = 'aurora';
        }
        else if (themePath.includes('retro')) {
            themeClassName = 'retro';
        }
        else if (themePath.includes('slate')) {
            themeClassName = 'slate';
        }
        else if (themePath.includes('light')) {
            themeClassName = 'light';
        }
    }
    document.body.classList.add(`theme-${themeClassName}`);

})();