ModernMonkeyConfig Enhanced Security Edition v0.4.0

Enhanced Security Configuration Dialog with improved performance, validation, and security features

بۇ قوليازمىنى بىۋاسىتە قاچىلاشقا بولمايدۇ. بۇ باشقا قوليازمىلارنىڭ ئىشلىتىشى ئۈچۈن تەمىنلەنگەن ئامبار بولۇپ، ئىشلىتىش ئۈچۈن مېتا كۆرسەتمىسىگە قىستۇرىدىغان كود: // @require https://update.greasyforks.org/scripts/549278/1666310/ModernMonkeyConfig%20Enhanced%20Security%20Edition%20v040.js

// ==UserScript==
// @name            ModernMonkeyConfig Enhanced Security Edition v0.4.2
// @noframes
// @version         0.4.2
// @namespace       http://odyniec.net/
// @include        *
// @description     Enhanced Security Configuration Dialog - Complete Organized Version
// @require         https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.5/purify.min.js#sha384-qSFej5dZNviyoPgYJ5+Xk4bEbX8AYddxAHPuzs1aSgRiXxJ3qmyWNaPsRkpv/+x5
// ==/UserScript==

/**
 * ModernMonkeyConfig - Enhanced Security Configuration Dialog
 * Complete organized version with improved maintainability and performance
 */
class ModernMonkeyConfig {
    constructor(data) {
        this.version = '0.4.2';
        this.initializeProperties();
        this.validateAndInitialize(data);
    }

    // ===========================================
    // INITIALIZATION METHODS
    // ===========================================

    /**
     * Initialize all class properties
     */
    initializeProperties() {
        this.data = null;
        this.params = {};
        this.values = {};
        this.storageKey = '';
        
        // UI State
        this.displayed = false;
        this.openLayer = null;
        this.shadowRoot = null;
        this.container = null;
        this.iframeFallback = null;
        
        // Caching and performance
        this.elementCache = new Map();
        this.eventListeners = new Map();
        this.validationRules = new Map();
        
        // Security
        this.trustedPolicy = null;
    }

    /**
     * Validate configuration data and initialize the system
     */
    validateAndInitialize(data) {
        try {
            this.data = this.validateAndSanitizeConfig(data);
            this.params = this.data.parameters || {};
            
            this.setupSecurity();
            this.setupValidationRules();
            this.setupStorage();
            this.loadStoredValues();
            
            if (this.data.menuCommand) {
                this.registerMenuCommand();
            }
            
            this.setupPublicMethods();
            this.log('ModernMonkeyConfig initialized successfully');
            
        } catch (error) {
            this.log(`Initialization failed: ${error.message}`, 'error');
            throw error;
        }
    }

    /**
     * Setup security measures
     */
    setupSecurity() {
        this.createTrustedPolicy();
    }

    /**
     * Setup validation rules
     */
    setupValidationRules() {
        this.validationRules.set('email', /^[^\s@]+@[^\s@]+\.[^\s@]+$/);
        this.validationRules.set('url', /^https?:\/\/.+/);
        this.validationRules.set('number', /^\d+$/);
        this.validationRules.set('float', /^\d*\.?\d+$/);
    }

    /**
     * Setup storage configuration
     */
    setupStorage() {
        this.storageKey = `_ModernMonkeyConfig_${this.data.title.replace(/[^a-zA-Z0-9]/g, '_')}_cfg`;
    }

    /**
     * Setup public methods with proper binding
     */
    setupPublicMethods() {
        this.open = this.open.bind(this);
        this.close = this.close.bind(this);
        this.get = this.get.bind(this);
        this.set = this.set.bind(this);
        this.validate = this.validate.bind(this);
        this.reset = this.reset.bind(this);
    }

    // ===========================================
    // VALIDATION AND SANITIZATION
    // ===========================================

    /**
     * Validate and sanitize the main configuration object
     */
    validateAndSanitizeConfig(data) {
        if (!data || typeof data !== 'object') {
            throw new Error('Configuration data must be an object');
        }

        const sanitized = {
            title: this.sanitizeString(data.title) || 'Configuration',
            buttons: this.sanitizeButtons(data.buttons),
            menuCommand: Boolean(data.menuCommand),
            parameters: {},
            ...this.sanitizeDimensions(data),
            onSave: typeof data.onSave === 'function' ? data.onSave : null
        };

        // Sanitize parameters
        if (data.parameters && typeof data.parameters === 'object') {
            sanitized.parameters = this.sanitizeParameters(data.parameters);
        }

        return sanitized;
    }

    /**
     * Sanitize button configuration
     */
    sanitizeButtons(buttons) {
        const validButtons = ['save', 'reset', 'close', 'reload', 'homepage'];
        return Array.isArray(buttons) 
            ? buttons.filter(btn => validButtons.includes(btn))
            : ['save', 'reset', 'close', 'reload', 'homepage'];
    }

    /**
     * Sanitize dimension and styling properties
     */
    sanitizeDimensions(data) {
        return {
            shadowWidth: this.validateDimension(data.shadowWidth) || '600px',
            shadowHeight: this.validateDimension(data.shadowHeight) || '400px',
            iframeWidth: this.validateDimension(data.iframeWidth) || '600px',
            iframeHeight: this.validateDimension(data.iframeHeight) || '400px',
            shadowFontSize: this.validateFontSize(data.shadowFontSize) || '14px',
            shadowFontColor: this.validateColor(data.shadowFontColor) || '#000000',
            iframeFontSize: this.validateFontSize(data.iframeFontSize) || '14px',
            iframeFontColor: this.validateColor(data.iframeFontColor) || '#000000'
        };
    }

    /**
     * Sanitize all parameters
     */
    sanitizeParameters(parameters) {
        const sanitized = {};
        
        for (const [key, param] of Object.entries(parameters)) {
            if (this.isValidParameterKey(key) && this.isValidParameter(param)) {
                sanitized[key] = this.sanitizeParameter(param);
            } else {
                this.log(`Invalid parameter skipped: ${key}`, 'warn');
            }
        }
        
        return sanitized;
    }

    /**
     * Sanitize individual parameter
     */
    sanitizeParameter(param) {
        const sanitized = {
            type: param.type,
            label: this.sanitizeString(param.label),
            default: this.sanitizeValue(param.default, param.type),
            column: this.validateColumn(param.column)
        };

        // Type-specific sanitization
        switch (param.type) {
            case 'number':
            case 'range':
                Object.assign(sanitized, this.sanitizeNumericParam(param));
                break;
            case 'textarea':
                Object.assign(sanitized, this.sanitizeTextareaParam(param));
                break;
            case 'radio':
            case 'select':
                Object.assign(sanitized, this.sanitizeChoiceParam(param));
                break;
            case 'file':
                sanitized.accept = this.sanitizeString(param.accept) || '*/*';
                break;
            case 'custom':
                Object.assign(sanitized, this.sanitizeCustomParam(param));
                break;
        }

        // Common styling properties
        this.sanitizeStyleProperties(param, sanitized);

        return sanitized;
    }

    /**
     * Sanitize numeric parameter properties
     */
    sanitizeNumericParam(param) {
        return {
            min: this.sanitizeNumber(param.min),
            max: this.sanitizeNumber(param.max),
            step: this.sanitizeNumber(param.step) || 1
        };
    }

    /**
     * Sanitize textarea parameter properties
     */
    sanitizeTextareaParam(param) {
        return {
            rows: Math.max(1, Math.min(20, parseInt(param.rows) || 4)),
            cols: Math.max(10, Math.min(100, parseInt(param.cols) || 20))
        };
    }

    /**
     * Sanitize choice-based parameter properties
     */
    sanitizeChoiceParam(param) {
        const result = {
            multiple: Boolean(param.multiple)
        };
        
        if (param.choices && typeof param.choices === 'object') {
            result.choices = this.sanitizeChoices(param.choices);
        }
        
        return result;
    }

    /**
     * Sanitize custom parameter properties
     */
    sanitizeCustomParam(param) {
        const result = {
            html: this.sanitizeString(param.html)
        };
        
        if (typeof param.get === 'function') result.get = param.get;
        if (typeof param.set === 'function') result.set = param.set;
        
        return result;
    }

    /**
     * Sanitize styling properties
     */
    sanitizeStyleProperties(param, sanitized) {
        const styleProps = ['fontSize', 'fontColor', 'inputWidth', 'inputHeight', 
                           'checkboxWidth', 'checkboxHeight'];
        
        styleProps.forEach(prop => {
            if (param[prop]) {
                sanitized[prop] = this.sanitizeString(param[prop]);
            }
        });
    }

    // ===========================================
    // BASIC SANITIZATION UTILITIES
    // ===========================================

    /**
     * Sanitize string input
     */
    sanitizeString(str) {
        if (typeof str !== 'string') return '';
        return str.trim().substring(0, 1000);
    }

    /**
     * Sanitize numeric input
     */
    sanitizeNumber(num) {
        const parsed = parseFloat(num);
        return isNaN(parsed) ? undefined : parsed;
    }

    /**
     * Sanitize value based on parameter type
     */
    sanitizeValue(value, type) {
        const sanitizers = {
            'number': () => this.sanitizeNumber(value),
            'range': () => this.sanitizeNumber(value),
            'checkbox': () => Boolean(value),
            'text': () => this.sanitizeString(value),
            'color': () => this.sanitizeString(value),
            'textarea': () => this.sanitizeString(value),
            'select': () => Array.isArray(value) 
                ? value.map(v => this.sanitizeString(v))
                : this.sanitizeString(value)
        };

        return sanitizers[type] ? sanitizers[type]() : value;
    }

    /**
     * Sanitize choice options
     */
    sanitizeChoices(choices) {
        const sanitized = {};
        
        for (const [key, value] of Object.entries(choices)) {
            const cleanKey = this.sanitizeString(key);
            const cleanValue = this.sanitizeString(value);
            if (cleanKey && cleanValue) {
                sanitized[cleanKey] = cleanValue;
            }
        }
        
        return sanitized;
    }

    // ===========================================
    // VALIDATION UTILITIES
    // ===========================================

    /**
     * Validate parameter key format
     */
    isValidParameterKey(key) {
        return typeof key === 'string' && 
               key.length > 0 && 
               key.length <= 50 && 
               /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key);
    }

    /**
     * Validate parameter structure
     */
    isValidParameter(param) {
        if (!param || typeof param !== 'object') return false;
        
        const validTypes = ['checkbox', 'number', 'text', 'color', 'textarea', 
                           'range', 'radio', 'file', 'button', 'select', 'group', 'custom'];
        
        return validTypes.includes(param.type);
    }

    /**
     * Validate column placement
     */
    validateColumn(column) {
        const validColumns = ['left', 'right', 'top', 'bottom', 
                             'left&top', 'right&top', 'left&bottom', 'right&bottom'];
        return validColumns.includes(column) ? column : null;
    }

    /**
     * Validate dimension strings
     */
    validateDimension(dimension) {
        if (typeof dimension !== 'string') return null;
        return /^\d+(px|em|rem|%|vh|vw)$/.test(dimension) ? dimension : null;
    }

    /**
     * Validate font size strings
     */
    validateFontSize(fontSize) {
        if (typeof fontSize !== 'string') return null;
        return /^\d+(px|em|rem)$/.test(fontSize) ? fontSize : null;
    }

    /**
     * Validate color strings
     */
    validateColor(color) {
        if (typeof color !== 'string') return null;
        return /^#([0-9A-Fa-f]{3}){1,2}$/.test(color) ? color : null;
    }

    // ===========================================
    // SECURITY AND TRUSTED TYPES
    // ===========================================

    /**
     * Create Trusted Types policy for secure HTML handling
     */
    createTrustedPolicy() {
        try {
            if (window.trustedTypes && window.trustedTypes.createPolicy) {
                this.trustedPolicy = window.trustedTypes.createPolicy(`monkeyConfig-${Date.now()}`, {
                    createHTML: (input) => this.sanitizeHTML(input)
                });
            } else {
                this.trustedPolicy = {
                    createHTML: (input) => this.fallbackSanitize(input)
                };
            }
        } catch (error) {
            this.log(`Failed to create Trusted Types policy: ${error.message}`, 'error');
            this.trustedPolicy = {
                createHTML: (input) => this.fallbackSanitize(input)
            };
        }
    }

    /**
     * Sanitize HTML using DOMPurify or fallback
     */
    sanitizeHTML(input) {
        if (typeof DOMPurify !== 'undefined') {
            return DOMPurify.sanitize(input, {
                ALLOWED_TAGS: ['div', 'span', 'table', 'tr', 'td', 'input', 'textarea', 
                              'button', 'label', 'select', 'option', 'fieldset', 'legend',
                              'h1', 'br', 'svg', 'path', 'style'],
                ALLOWED_ATTR: ['type', 'name', 'id', 'class', 'style', 'for', 'value', 
                              'min', 'max', 'step', 'rows', 'cols', 'multiple', 'accept',
                              'width', 'height', 'viewBox', 'fill', 'stroke', 'stroke-width',
                              'stroke-linecap', 'stroke-linejoin', 'd', 'colspan', 'checked'],
                ALLOW_DATA_ATTR: false,
                RETURN_TRUSTED_TYPE: true
            });
        } else {
            this.log('DOMPurify not available, using fallback sanitization', 'warn');
            return this.fallbackSanitize(input);
        }
    }

    /**
     * Fallback HTML sanitization
     */
    fallbackSanitize(input) {
        return String(input)
            .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
            .replace(/on\w+\s*=\s*"[^"]*"/gi, '')
            .replace(/on\w+\s*=\s*'[^']*'/gi, '')
            .replace(/javascript:/gi, '')
            .replace(/vbscript:/gi, '')
            .replace(/data:/gi, '');
    }

    /**
     * Create trusted HTML content
     */
    createTrustedHTML(htmlString) {
        try {
            return this.trustedPolicy.createHTML(htmlString);
        } catch (error) {
            this.log(`Failed to create TrustedHTML: ${error.message}`, 'error');
            return '';
        }
    }

    // ===========================================
    // STORAGE AND VALUES MANAGEMENT
    // ===========================================

    /**
     * Load stored configuration values
     */
    loadStoredValues() {
        try {
            let storedValues = this.getStoredData();
            
            // Load UI settings
            this.loadUISettings(storedValues);
            
            // Load parameter values
            this.loadParameterValues(storedValues);
            
        } catch (error) {
            this.log(`Failed to load stored values: ${error.message}`, 'error');
            this.loadDefaultValues();
        }
    }

    /**
     * Get stored data from appropriate storage
     */
    getStoredData() {
        try {
            if (typeof GM_getValue !== 'undefined') {
                const stored = GM_getValue(this.storageKey);
                return stored ? JSON.parse(stored) : {};
            }
            return {};
        } catch {
            return {};
        }
    }

    /**
     * Load UI-related settings
     */
    loadUISettings(storedValues) {
        this.shadowWidth = this.validateDimension(storedValues.shadowWidth) || this.data.shadowWidth;
        this.shadowHeight = this.validateDimension(storedValues.shadowHeight) || this.data.shadowHeight;
        this.iframeWidth = this.validateDimension(storedValues.iframeWidth) || this.data.iframeWidth;
        this.iframeHeight = this.validateDimension(storedValues.iframeHeight) || this.data.iframeHeight;
        this.shadowFontSize = this.validateFontSize(storedValues.shadowFontSize) || this.data.shadowFontSize;
        this.shadowFontColor = this.validateColor(storedValues.shadowFontColor) || this.data.shadowFontColor;
        this.iframeFontSize = this.validateFontSize(storedValues.iframeFontSize) || this.data.iframeFontSize;
        this.iframeFontColor = this.validateColor(storedValues.iframeFontColor) || this.data.iframeFontColor;
    }

    /**
     * Load parameter values
     */
    loadParameterValues(storedValues) {
        for (const [key, param] of Object.entries(this.params)) {
            this.values[key] = storedValues[key] !== undefined 
                ? this.sanitizeValue(storedValues[key], param.type)
                : param.default;
        }
    }

    /**
     * Load default values for all parameters
     */
    loadDefaultValues() {
        for (const [key, param] of Object.entries(this.params)) {
            this.values[key] = param.default;
        }
    }

    /**
     * Save current configuration to storage
     */
    save() {
        try {
            const errors = this.validate();
            if (errors.length > 0) {
                alert('Validation errors:\n' + errors.join('\n'));
                return false;
            }

            const dataToSave = this.prepareDataForSaving();

            if (typeof GM_setValue !== 'undefined') {
                GM_setValue(this.storageKey, JSON.stringify(dataToSave));
                this.log('Settings saved successfully');
            } else {
                this.log('GM_setValue not available, cannot save settings', 'warn');
                return false;
            }

            this.executeOnSaveCallback();
            return true;
            
        } catch (error) {
            this.log(`Failed to save settings: ${error.message}`, 'error');
            alert('Failed to save settings. Please check console for details.');
            return false;
        }
    }

    /**
     * Prepare data structure for saving
     */
    prepareDataForSaving() {
        return {
            ...this.values,
            shadowWidth: this.shadowWidth,
            shadowHeight: this.shadowHeight,
            iframeWidth: this.iframeWidth,
            iframeHeight: this.iframeHeight,
            shadowFontSize: this.shadowFontSize,
            shadowFontColor: this.shadowFontColor,
            iframeFontSize: this.iframeFontSize,
            iframeFontColor: this.iframeFontColor
        };
    }

    /**
     * Execute onSave callback if provided
     */
    executeOnSaveCallback() {
        if (this.data.onSave && typeof this.data.onSave === 'function') {
            try {
                this.data.onSave(this.values);
            } catch (error) {
                this.log(`Error in onSave callback: ${error.message}`, 'error');
            }
        }
    }

    // ===========================================
    // PUBLIC API METHODS
    // ===========================================

    /**
     * Get parameter value
     */
    get(name) {
        if (!this.params[name]) {
            this.log(`Parameter '${name}' does not exist`, 'warn');
            return undefined;
        }
        return this.values[name];
    }

    /**
     * Set parameter value
     */
    set(name, value) {
        try {
            if (!this.params[name]) {
                this.log(`Parameter '${name}' does not exist`, 'warn');
                return false;
            }
            
            const sanitizedValue = this.sanitizeValue(value, this.params[name].type);
            
            if (this.validateValue(name, sanitizedValue)) {
                this.values[name] = sanitizedValue;
                this.updateUI();
                return true;
            }
            
            return false;
        } catch (error) {
            this.log(`Failed to set value for ${name}: ${error.message}`, 'error');
            return false;
        }
    }

    /**
     * Reset all values to defaults
     */
    reset() {
        try {
            for (const [key, param] of Object.entries(this.params)) {
                this.values[key] = param.default;
            }
            this.updateUI();
            this.log('Configuration reset to defaults');
        } catch (error) {
            this.log(`Failed to reset configuration: ${error.message}`, 'error');
        }
    }

    /**
     * Validate all current values
     */
    validate() {
        const errors = [];
        
        for (const [name, value] of Object.entries(this.values)) {
            if (!this.validateValue(name, value)) {
                errors.push(`Invalid value for parameter '${name}': ${value}`);
            }
        }
        
        return errors;
    }

    /**
     * Validate individual value
     */
    validateValue(name, value) {
        const param = this.params[name];
        if (!param) return false;

        const validators = {
            'number': (val, p) => this.validateNumericValue(val, p),
            'range': (val, p) => this.validateNumericValue(val, p),
            'text': (val, p) => this.validateTextValue(val, p),
            'checkbox': (val) => typeof val === 'boolean'
        };

        const validator = validators[param.type];
        return validator ? validator(value, param) : true;
    }

    /**
     * Validate numeric values
     */
    validateNumericValue(value, param) {
        const num = parseFloat(value);
        if (isNaN(num)) return false;
        if (param.min !== undefined && num < param.min) return false;
        if (param.max !== undefined && num > param.max) return false;
        return true;
    }

    /**
     * Validate text values
     */
    validateTextValue(value, param) {
        if (typeof value !== 'string') return false;
        if (value.length > 1000) return false;
        
        if (param.validation && this.validationRules.has(param.validation)) {
            return this.validationRules.get(param.validation).test(value);
        }
        
        return true;
    }

    // ===========================================
    // UTILITY METHODS
    // ===========================================

    /**
     * Register menu command with userscript manager
     */
    registerMenuCommand() {
        try {
            if (typeof GM_registerMenuCommand !== 'undefined') {
                const commandText = this.data.menuCommand === true 
                    ? this.data.title 
                    : String(this.data.menuCommand);
                
                GM_registerMenuCommand(commandText, () => this.open());
            }
        } catch (error) {
            this.log(`Failed to register menu command: ${error.message}`, 'error');
        }
    }

    /**
     * Log messages with timestamp and context
     */
    log(message, level = 'info') {
        try {
            const timestamp = new Date().toISOString();
            const formattedMessage = `[ModernMonkeyConfig v${this.version}] ${timestamp}: ${message}`;
            
            if (console[level]) {
                console[level](formattedMessage);
            } else {
                console.log(`[${level.toUpperCase()}] ${formattedMessage}`);
            }
        } catch (error) {
            console.error(`[ModernMonkeyConfig v${this.version}] Logging failed: ${error.message}`);
        }
    }

    /**
     * Escape HTML for safe display
     */
    escapeHtml(string) {
        if (string == null) return '';
        return String(string)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
    }

    // ===========================================
    // UI RENDERING AND MANAGEMENT
    // ===========================================

    /**
     * Open the configuration dialog
     */
    open() {
        if (this.displayed) {
            this.log('Configuration dialog is already open', 'warn');
            return;
        }

        try {
            this.createShadowDOM();
            this.displayed = true;
            this.log('Configuration dialog opened');
        } catch (error) {
            this.log(`Failed to open configuration dialog: ${error.message}`, 'error');
            this.createIframeFallback();
        }
    }

    /**
     * Close the configuration dialog
     */
    close() {
        try {
            if (!this.displayed) return;

            this.removeEventListeners();
            this.removeDOMElements();
            this.clearReferences();
            
            this.displayed = false;
            this.log('Configuration dialog closed');
        } catch (error) {
            this.log(`Error closing dialog: ${error.message}`, 'error');
        }
    }

    /**
     * Remove all event listeners
     */
    removeEventListeners() {
        for (const [event, handler] of this.eventListeners) {
            document.removeEventListener(event, handler);
        }
        this.eventListeners.clear();
    }

    /**
     * Remove DOM elements
     */
    removeDOMElements() {
        if (this.openLayer && this.openLayer.parentNode) {
            this.openLayer.parentNode.removeChild(this.openLayer);
        }
    }

    /**
     * Clear object references
     */
    clearReferences() {
        this.openLayer = null;
        this.shadowRoot = null;
        this.container = null;
        this.iframeFallback = null;
        this.elementCache.clear();
    }

    /**
     * Enhanced Shadow DOM creation with proper event isolation
     */
    createShadowDOM() {
        try {
            this.createOverlay();
            
            if (this.openLayer.attachShadow) {
                this.shadowRoot = this.openLayer.attachShadow({ mode: 'closed' });
                this.populateShadowDOM();
                
                // منع انتشار أحداث النقر من Shadow DOM إلى الخلفية
                const container = this.shadowRoot.querySelector('.__MonkeyConfig_container');
                if (container) {
                    container.addEventListener('click', (e) => {
                        e.stopPropagation();
                    });
                }
            } else {
                throw new Error('Shadow DOM not supported');
            }

            document.body.appendChild(this.openLayer);
            this.attachEventListeners();
            this.focusFirstElement();
            
        } catch (error) {
            this.log(`Failed to create Shadow DOM: ${error.message}`, 'error');
            throw error;
        }
    }

    /**
     * Create overlay element
     */
    createOverlay() {
        this.openLayer = document.createElement('div');
        this.openLayer.style.cssText = `
            position: fixed !important;
            top: 0 !important;
            left: 0 !important;
            width: 100% !important;
            height: 100% !important;
            background: rgba(0, 0, 0, 0.5) !important;
            z-index: 2147483646 !important;
            backdrop-filter: blur(2px) !important;
        `;
    }

    /**
     * Populate Shadow DOM with content
     */
    populateShadowDOM() {
        const container = document.createElement('div');
        container.innerHTML = this.getCSS() + this.render();
        this.shadowRoot.appendChild(container);
        this.container = this.shadowRoot.querySelector('.__MonkeyConfig_container');
    }

    /**
     * Focus first interactive element
     */
    focusFirstElement() {
        setTimeout(() => {
            const firstInput = this.shadowRoot.querySelector('input, textarea, select, button');
            if (firstInput) firstInput.focus();
        }, 100);
    }

    /**
     * Create iframe fallback when Shadow DOM fails
     */
    createIframeFallback() {
        try {
            this.log('Using iframe fallback', 'info');
            
            this.createOverlay();
            this.createIframe();
            this.populateIframe();
            
            document.body.appendChild(this.openLayer);
            
            // منع إغلاق النافذة عند النقر داخل الإطار
            this.preventIframeBackdropClose();
            
            this.attachEventListeners(this.iframeFallback.contentDocument);
            this.displayed = true;

        } catch (error) {
            this.log(`Failed to create iframe fallback: ${error.message}`, 'error');
            alert('Failed to open configuration dialog. Please check console for details.');
        }
    }

    /**
     * Create iframe element
     */
    createIframe() {
        this.iframeFallback = document.createElement('iframe');
        this.iframeFallback.style.cssText = `
            position: absolute !important;
            top: 50% !important;
            left: 50% !important;
            transform: translate(-50%, -50%) !important;
            width: ${this.iframeWidth} !important;
            height: ${this.iframeHeight} !important;
            border: none !important;
            border-radius: 8px !important;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
        `;
        
        this.openLayer.appendChild(this.iframeFallback);
    }

    /**
     * Populate iframe with content
     */
    populateIframe() {
        const iframeDoc = this.iframeFallback.contentDocument || this.iframeFallback.contentWindow.document;
        
        const html = `
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="utf-8">
                <meta name="viewport" content="width=device-width, initial-scale=1">
                <title>${this.escapeHtml(this.data.title)}</title>
                ${this.getIframeCSS()}
            </head>
            <body style="margin:0;padding:0;overflow:hidden;">
                ${this.render()}
            </body>
            </html>
        `;

        iframeDoc.open();
        iframeDoc.write(html);
        iframeDoc.close();

        this.container = iframeDoc.querySelector('.__MonkeyConfig_container');
    }

    /**
     * Get CSS adapted for iframe
     */
    getIframeCSS() {
        return this.getCSS()
            .replace(new RegExp(this.shadowFontSize, 'g'), this.iframeFontSize)
            .replace(new RegExp(this.shadowFontColor, 'g'), this.iframeFontColor);
    }

    /**
     * Prevent iframe content clicks from bubbling to backdrop
     */
    preventIframeBackdropClose() {
        if (this.iframeFallback) {
            // منع انتشار أحداث النقر من داخل الإطار إلى الخلفية
            this.iframeFallback.addEventListener('click', (e) => {
                e.stopPropagation();
            });
            
            // منع انتشار الأحداث من محتوى الإطار
            const iframeDoc = this.iframeFallback.contentDocument || this.iframeFallback.contentWindow.document;
            if (iframeDoc) {
                iframeDoc.addEventListener('click', (e) => {
                    e.stopPropagation();
                });
            }
        }
    }

    /**
     * Attach event listeners to the dialog
     */
    attachEventListeners(doc = null) {
        try {
            const context = doc || this.shadowRoot;
            if (!context) return;

            const container = context.querySelector('.__MonkeyConfig_container');
            if (!container) return;

            // Single event listener with delegation for better performance
            const handleEvent = (e) => {
                this.handleDialogEvent(e);
            };

            // Attach delegated event listeners
            container.addEventListener('click', handleEvent);
            container.addEventListener('change', handleEvent);
            container.addEventListener('input', handleEvent);

            // Backdrop click to close
            this.attachBackdropListener();
            
            // Keyboard shortcuts
            this.attachKeyboardListeners(doc);
            
            this.log('Event listeners attached');

        } catch (error) {
            this.log(`Failed to attach event listeners: ${error.message}`, 'error');
        }
    }

    /**
     * Handle dialog events with delegation
     */
    handleDialogEvent(e) {
        const target = e.target;
        const targetId = target.id;
        const targetName = target.name;

        // Button clicks
        if (targetId && targetId.startsWith('__MonkeyConfig_button_')) {
            e.preventDefault();
            const buttonType = targetId.replace('__MonkeyConfig_button_', '');
            this.handleButtonClick(buttonType);
            return;
        }

        // Form field changes
        if (targetName && this.params[targetName]) {
            this.handleFieldChange(targetName, target);
            return;
        }
    }

    /**
     * Attach backdrop click listener with improved logic
     */
    attachBackdropListener() {
        if (this.openLayer) {
            this.openLayer.addEventListener('click', (e) => {
                // التحقق من أن النقر كان على الخلفية المظلمة وليس على أي محتوى داخلي
                const clickTarget = e.target;
                const container = this.shadowRoot ? 
                    this.shadowRoot.querySelector('.__MonkeyConfig_container') : 
                    (this.iframeFallback ? this.iframeFallback : null);
                
                // إغلاق فقط عند النقر على الـ overlay نفسه، وليس على المحتوى
                if (clickTarget === this.openLayer) {
                    this.close();
                }
            });
        }
    }

    /**
     * Attach keyboard event listeners
     */
    attachKeyboardListeners(doc) {
        const handleKeyDown = (e) => {
            if (e.key === 'Escape') {
                this.close();
            } else if (e.key === 's' && (e.ctrlKey || e.metaKey)) {
                e.preventDefault();
                this.handleButtonClick('save');
            }
        };

        (doc || document).addEventListener('keydown', handleKeyDown);
        this.eventListeners.set('keydown', handleKeyDown);
    }

    /**
     * Handle button click events
     */
    handleButtonClick(buttonType) {
        try {
            const handlers = {
                'save': () => this.save(),
                'reset': () => this.handleReset(),
                'close': () => this.close(),
                'reload': () => this.handleReload(),
                'homepage': () => this.handleHomepage()
            };

            const handler = handlers[buttonType];
            if (handler) {
                handler();
            } else {
                this.log(`Unknown button type: ${buttonType}`, 'warn');
            }
        } catch (error) {
            this.log(`Error handling button click (${buttonType}): ${error.message}`, 'error');
        }
    }

    /**
     * Handle reset button click
     */
    handleReset() {
        if (confirm('Are you sure you want to reset all settings to default values?')) {
            this.reset();
        }
    }

    /**
     * Handle reload button click
     */
    handleReload() {
        this.save();
        if (typeof GM_getValue !== 'undefined') {
            location.reload();
        } else {
            alert('Settings saved. Please refresh the page manually.');
        }
    }

    /**
     * Handle homepage button click
     */
    handleHomepage() {
        if (typeof GM_info !== 'undefined' && GM_info.script && GM_info.script.homepage) {
            window.open(GM_info.script.homepage, '_blank');
        } else {
            alert('Homepage not available');
        }
    }

    /**
     * Handle form field changes
     */
    handleFieldChange(name, element) {
        try {
            const param = this.params[name];
            if (!param) return;

            const value = this.extractFieldValue(param, element);
            
            if (this.validateValue(name, value)) {
                this.values[name] = value;
                
                // Update UI for range sliders
                if (param.type === 'range') {
                    this.updateRangeDisplay(element, value);
                }
                
                this.log(`Field '${name}' updated to: ${value}`);
            } else {
                this.log(`Invalid value for field '${name}': ${value}`, 'warn');
                this.revertFieldValue(element, name);
            }

        } catch (error) {
            this.log(`Error handling field change (${name}): ${error.message}`, 'error');
        }
    }

    /**
     * Extract value from form field based on type
     */
    extractFieldValue(param, element) {
        switch (param.type) {
            case 'checkbox':
                return element.checked;
            case 'number':
            case 'range':
                const num = parseFloat(element.value);
                return isNaN(num) ? param.default : num;
            case 'select':
                return param.multiple 
                    ? Array.from(element.selectedOptions).map(option => option.value)
                    : element.value;
            case 'custom':
                return param.get && typeof param.get === 'function'
                    ? param.get(element)
                    : element.value;
            default:
                return element.value;
        }
    }

    /**
     * Update range slider display
     */
    updateRangeDisplay(element, value) {
        const rangeValue = element.parentNode.querySelector('.__MonkeyConfig_range_value');
        if (rangeValue) {
            rangeValue.textContent = value;
        }
    }

    /**
     * Revert field to previous valid value
     */
    revertFieldValue(element, name) {
        const previousValue = this.values[name];
        const param = this.params[name];
        
        switch (param.type) {
            case 'checkbox':
                element.checked = Boolean(previousValue);
                break;
            case 'select':
                element.value = previousValue;
                break;
            default:
                element.value = previousValue || '';
        }
    }

    /**
     * Update UI elements with current values
     */
    updateUI() {
        try {
            const context = this.shadowRoot || (this.iframeFallback && this.iframeFallback.contentDocument);
            if (!context) return;

            for (const [name, value] of Object.entries(this.values)) {
                const param = this.params[name];
                if (!param) continue;

                this.updateFieldValue(context, name, param, value);
            }

        } catch (error) {
            this.log(`Error updating UI: ${error.message}`, 'error');
        }
    }

    /**
     * Update individual field value in UI
     */
    updateFieldValue(context, name, param, value) {
        const element = context.querySelector(`[name="${name}"]`);
        if (!element) return;

        switch (param.type) {
            case 'checkbox':
                element.checked = Boolean(value);
                break;
            case 'select':
                this.updateSelectValue(element, param, value);
                break;
            case 'radio':
                this.updateRadioValue(context, name, value);
                break;
            case 'range':
                this.updateRangeValue(element, value);
                break;
            case 'custom':
                this.updateCustomValue(element, param, value);
                break;
            default:
                element.value = value || '';
        }
    }

    /**
     * Update select field value
     */
    updateSelectValue(element, param, value) {
        if (param.multiple && Array.isArray(value)) {
            Array.from(element.options).forEach(option => {
                option.selected = value.includes(option.value);
            });
        } else {
            element.value = value;
        }
    }

    /**
     * Update radio button value
     */
    updateRadioValue(context, name, value) {
        const radioButton = context.querySelector(`[name="${name}"][value="${value}"]`);
        if (radioButton) radioButton.checked = true;
    }

    /**
     * Update range slider value and display
     */
    updateRangeValue(element, value) {
        element.value = value;
        const rangeValue = element.parentNode.querySelector('.__MonkeyConfig_range_value');
        if (rangeValue) rangeValue.textContent = value;
    }

    /**
     * Update custom field value
     */
    updateCustomValue(element, param, value) {
        if (param.set && typeof param.set === 'function') {
            param.set(element, value);
        } else {
            element.value = value;
        }
    }

    // ===========================================
    // UI RENDERING IMPLEMENTATION
    // ===========================================

    /**
     * Render main HTML content
     */
    render() {
        try {
            const title = this.escapeHtml(this.data.title);
            
            let html = `
                <div class="__MonkeyConfig_container">
                    ${this.renderHeader(title)}
                    ${this.renderContent()}
                    ${this.renderFooter()}
                </div>`;
            
            return this.createTrustedHTML(html);
        } catch (error) {
            this.log(`Failed to render HTML: ${error.message}`, 'error');
            return this.createTrustedHTML('<div class="__MonkeyConfig_error">Error rendering configuration dialog</div>');
        }
    }

    /**
     * Render dialog header
     */
    renderHeader(title) {
        return `
            <div class="__MonkeyConfig_header">
                <h1>${title}</h1>
                <button type="button" id="__MonkeyConfig_button_close" class="__MonkeyConfig_close_btn" aria-label="Close">
                    ${this.getIcon('close')}
                </button>
            </div>`;
    }

    /**
     * Render main content area
     */
    renderContent() {
        return `
            <div class="__MonkeyConfig_content">
                <div class="__MonkeyConfig_sections">
                    ${this.renderSections()}
                </div>
            </div>`;
    }

    /**
     * Render all sections
     */
    renderSections() {
        let html = '';
        html += this.renderSection('top');
        html += this.renderColumns('top');
        html += this.renderColumns('middle');
        html += this.renderDefaultSection();
        html += this.renderColumns('bottom');
        html += this.renderSection('bottom');
        return html;
    }

    /**
     * Render positioned section
     */
    renderSection(position) {
        const items = Object.entries(this.params)
            .filter(([, param]) => param.column === position)
            .map(([key, param]) => this.renderField(key, param))
            .join('');
        
        return items ? `<div class="__MonkeyConfig_section_${position}">${items}</div>` : '';
    }

    /**
     * Render column layout
     */
    renderColumns(position) {
        const leftColumn = position !== 'middle' ? `left&${position}` : 'left';
        const rightColumn = position !== 'middle' ? `right&${position}` : 'right';
        
        const leftItems = this.getColumnItems(leftColumn);
        const rightItems = this.getColumnItems(rightColumn);
        
        if (!leftItems && !rightItems) return '';
        
        return `
            <div class="__MonkeyConfig_columns">
                <div class="__MonkeyConfig_left_column">${leftItems}</div>
                <div class="__MonkeyConfig_right_column">${rightItems}</div>
            </div>`;
    }

    /**
     * Get items for specific column
     */
    getColumnItems(column) {
        return Object.entries(this.params)
            .filter(([, param]) => param.column === column)
            .map(([key, param]) => this.renderField(key, param))
            .join('');
    }

    /**
     * Render default section (table layout)
     */
    renderDefaultSection() {
        const items = Object.entries(this.params)
            .filter(([, param]) => !param.column)
            .map(([key, param]) => this.renderField(key, param))
            .join('');
        
        return items ? `<table class="__MonkeyConfig_default_table">${items}</table>` : '';
    }

    /**
     * Render individual field
     */
    renderField(name, param) {
        const fieldId = `__MonkeyConfig_field_${this.escapeHtml(name)}`;
        const parentId = `__MonkeyConfig_parent_${this.escapeHtml(name)}`;
        
        const label = this.renderLabel(name, param, fieldId);
        const field = this.renderInput(name, param, fieldId);
        
        if (param.type === 'group') {
            return `<tr><td colspan="2">${field}</td></tr>`;
        }
        
        const isInline = ['checkbox', 'number', 'text'].includes(param.type);
        
        if (isInline) {
            return `
                <tr>
                    <td id="${parentId}" colspan="2" class="__MonkeyConfig_inline">
                        ${label}${field}
                    </td>
                </tr>`;
        }
        
        return `
            <tr>
                <td class="__MonkeyConfig_label_cell">${label}</td>
                <td id="${parentId}" class="__MonkeyConfig_field_cell">${field}</td>
            </tr>`;
    }

    /**
     * Render field label
     */
    renderLabel(name, param, fieldId) {
        const labelText = param.label || 
            name.charAt(0).toUpperCase() + name.slice(1).replace(/_/g, ' ');
        
        const styles = this.getLabelStyles(param);
        const styleAttr = styles.length ? ` style="${styles.join(';')}"` : '';
        
        return `<label for="${fieldId}"${styleAttr}>${this.escapeHtml(labelText)}</label>`;
    }

    /**
     * Get label styling
     */
    getLabelStyles(param) {
        const styles = [];
        if (param.fontSize) styles.push(`font-size:${this.escapeHtml(param.fontSize)}`);
        if (param.fontColor) styles.push(`color:${this.escapeHtml(param.fontColor)}`);
        if (param.labelAlign) styles.push(`text-align:${this.escapeHtml(param.labelAlign)}`);
        return styles;
    }

    /**
     * Render input field based on type
     */
    renderInput(name, param, fieldId) {
        const inputName = this.escapeHtml(name);
        const value = this.values[name];
        
        const renderers = {
            'checkbox': () => this.renderCheckbox(fieldId, inputName, value),
            'number': () => this.renderNumber(fieldId, inputName, param, value),
            'text': () => this.renderText(fieldId, inputName, value),
            'color': () => this.renderColor(fieldId, inputName, value),
            'textarea': () => this.renderTextarea(fieldId, inputName, param, value),
            'range': () => this.renderRange(fieldId, inputName, param, value),
            'select': () => this.renderSelect(fieldId, inputName, param, value),
            'radio': () => this.renderRadio(fieldId, inputName, param, value),
            'file': () => this.renderFile(fieldId, inputName, param),
            'button': () => this.renderButton(fieldId, inputName, param),
            'group': () => this.renderGroup(fieldId, inputName, param),
            'custom': () => this.renderCustom(fieldId, inputName, param)
        };

        const renderer = renderers[param.type];
        return renderer ? renderer() : this.renderError(param.type);
    }

    /**
     * Render checkbox input
     */
    renderCheckbox(fieldId, inputName, value) {
        return `<input type="checkbox" id="${fieldId}" name="${inputName}" ${value ? 'checked' : ''}>`;
    }

    /**
     * Render number input
     */
    renderNumber(fieldId, inputName, param, value) {
        const attributes = [];
        if (param.min !== undefined) attributes.push(`min="${param.min}"`);
        if (param.max !== undefined) attributes.push(`max="${param.max}"`);
        if (param.step !== undefined) attributes.push(`step="${param.step}"`);
        
        return `<input type="number" id="${fieldId}" name="${inputName}" 
                value="${this.escapeHtml(value || '')}" ${attributes.join(' ')}>`;
    }

    /**
     * Render text input
     */
    renderText(fieldId, inputName, value) {
        return `<input type="text" id="${fieldId}" name="${inputName}" 
                value="${this.escapeHtml(value || '')}">`;
    }

    /**
     * Render color input
     */
    renderColor(fieldId, inputName, value) {
        return `<input type="color" id="${fieldId}" name="${inputName}" 
                value="${this.escapeHtml(value || '#000000')}">`;
    }

    /**
     * Render textarea
     */
    renderTextarea(fieldId, inputName, param, value) {
        return `<textarea id="${fieldId}" name="${inputName}" 
                rows="${param.rows || 4}" cols="${param.cols || 20}">${this.escapeHtml(value || '')}</textarea>`;
    }

    /**
     * Render range input
     */
    renderRange(fieldId, inputName, param, value) {
        const currentValue = value || param.min || 0;
        return `<input type="range" id="${fieldId}" name="${inputName}" 
                value="${currentValue}" min="${param.min || 0}" max="${param.max || 100}" 
                step="${param.step || 1}">
                <span class="__MonkeyConfig_range_value">${currentValue}</span>`;
    }

    /**
     * Render select dropdown
     */
    renderSelect(fieldId, inputName, param, value) {
        const multipleAttr = param.multiple ? ' multiple' : '';
        const selectedValues = Array.isArray(value) ? value : [value];
        
        let options = '';
        if (param.choices) {
            for (const [key, label] of Object.entries(param.choices)) {
                const selected = selectedValues.includes(key) ? ' selected' : '';
                options += `<option value="${this.escapeHtml(key)}"${selected}>${this.escapeHtml(label)}</option>`;
            }
        }
        
        return `<select id="${fieldId}" name="${inputName}"${multipleAttr}>${options}</select>`;
    }

    /**
     * Render radio buttons
     */
    renderRadio(fieldId, inputName, param, value) {
        let radioHtml = '<div class="__MonkeyConfig_radio_group">';
        
        if (param.choices) {
            for (const [key, label] of Object.entries(param.choices)) {
                const checked = value === key ? ' checked' : '';
                const radioId = `${fieldId}_${key}`;
                radioHtml += `
                    <label class="__MonkeyConfig_radio_label">
                        <input type="radio" id="${radioId}" name="${inputName}" 
                               value="${this.escapeHtml(key)}"${checked}>
                        ${this.escapeHtml(label)}
                    </label>`;
            }
        }
        
        radioHtml += '</div>';
        return radioHtml;
    }

    /**
     * Render file input
     */
    renderFile(fieldId, inputName, param) {
        return `<input type="file" id="${fieldId}" name="${inputName}" 
                accept="${this.escapeHtml(param.accept || '*/*')}">`;
    }

    /**
     * Render button
     */
    renderButton(fieldId, inputName, param) {
        return `<button type="button" id="${fieldId}" name="${inputName}" 
                class="__MonkeyConfig_custom_button">${this.escapeHtml(param.label || 'Button')}</button>`;
    }

    /**
     * Render group fieldset
     */
    renderGroup(fieldId, inputName, param) {
        const legend = param.label ? `<legend>${this.escapeHtml(param.label)}</legend>` : '';
        return `<fieldset id="${fieldId}" class="__MonkeyConfig_group">${legend}</fieldset>`;
    }

    /**
     * Render custom field
     */
    renderCustom(fieldId, inputName, param) {
        const customHtml = param.html || '';
        return `<div id="${fieldId}" class="__MonkeyConfig_custom" data-name="${inputName}">${customHtml}</div>`;
    }

    /**
     * Render error message
     */
    renderError(type) {
        return `<span class="__MonkeyConfig_error">Unknown field type: ${this.escapeHtml(type)}</span>`;
    }

    /**
     * Render footer with buttons
     */
    renderFooter() {
        return `
            <div class="__MonkeyConfig_footer">
                ${this.renderButtons()}
            </div>`;
    }

    /**
     * Render action buttons
     */
    renderButtons() {
        let buttonsHtml = '';
        
        for (const buttonType of this.data.buttons) {
            if (buttonType === 'close') continue; // Close button is in header
            
            const buttonId = `__MonkeyConfig_button_${buttonType}`;
            const buttonText = this.getButtonText(buttonType);
            const icon = this.getIcon(buttonType);
            
            buttonsHtml += `
                <button type="button" id="${buttonId}" class="__MonkeyConfig_btn __MonkeyConfig_btn_${buttonType}">
                    ${icon}
                    <span>${buttonText}</span>
                </button>`;
        }
        
        return buttonsHtml;
    }

    /**
     * Get icon SVG for button type
     */
    getIcon(type) {
        const icons = {
            save: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 6 9 17l-5-5"/></svg>',
            reset: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>',
            close: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',
            reload: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"/><path d="M16 16h5v5"/></svg>',
            homepage: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"/><path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>'
        };
        return icons[type] || '';
    }

    /**
     * Get button text
     */
    getButtonText(buttonType) {
        const texts = {
            save: 'Save Without Reload',
            reset: 'Reset',
            reload: 'Save With Reload',
            homepage: 'Homepage'
        };
        return texts[buttonType] || buttonType;
    }

    /**
     * Get complete CSS styles
     */
    getCSS() {
        return `
            <style>
                .__MonkeyConfig_container {
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    width: ${this.shadowWidth};
                    max-width: 90vw;
                    height: ${this.shadowHeight};
                    max-height: 90vh;
                    background: #ffffff;
                    border: 1px solid #ddd;
                    border-radius: 8px;
                    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
                    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                    font-size: ${this.shadowFontSize};
                    color: ${this.shadowFontColor};
                    z-index: 2147483647;
                    display: flex;
                    flex-direction: column;
                    overflow: hidden;
                    animation: __MonkeyConfig_fadeIn 0.3s ease-out;
                }

                .__MonkeyConfig_header {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    padding: 16px 20px;
                    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                    color: white;
                    border-radius: 8px 8px 0 0;
                }

                .__MonkeyConfig_header h1 {
                    margin: 0;
                    font-size: 18px;
                    font-weight: 600;
                    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
                }

                .__MonkeyConfig_close_btn {
                    background: rgba(255, 255, 255, 0.1);
                    border: 1px solid rgba(255, 255, 255, 0.2);
                    color: white;
                    width: 32px;
                    height: 32px;
                    border-radius: 50%;
                    cursor: pointer;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    transition: all 0.2s ease;
                }

                .__MonkeyConfig_close_btn:hover {
                    background: rgba(255, 255, 255, 0.2);
                    transform: scale(1.1);
                }

                .__MonkeyConfig_content {
                    flex: 1;
                    padding: 20px;
                    overflow-y: auto;
                    overflow-x: hidden;
                }

                .__MonkeyConfig_sections {
                    display: flex;
                    flex-direction: column;
                    gap: 20px;
                }

                .__MonkeyConfig_columns {
                    display: grid;
                    grid-template-columns: 1fr 1fr;
                    gap: 20px;
                }

                .__MonkeyConfig_default_table {
                    width: 100%;
                    border-collapse: collapse;
                }

                .__MonkeyConfig_default_table tr {
                    border-bottom: 1px solid #f0f0f0;
                }

                .__MonkeyConfig_default_table td {
                    padding: 12px 8px;
                    vertical-align: top;
                }

                .__MonkeyConfig_label_cell {
                    width: 30%;
                    font-weight: 500;
                    color: #333;
                }

                .__MonkeyConfig_field_cell {
                    width: 70%;
                }

                .__MonkeyConfig_inline {
                    display: flex;
                    align-items: center;
                    gap: 12px;
                }

                .__MonkeyConfig_inline label {
                    margin: 0;
                    font-weight: 500;
                }

                /* Form Controls */
                .__MonkeyConfig_container input,
                .__MonkeyConfig_container textarea,
                .__MonkeyConfig_container select {
                    border: 2px solid #e1e5e9;
                    border-radius: 6px;
                    padding: 8px 12px;
                    font-size: 14px;
                    transition: all 0.2s ease;
                    background: white;
                }

                .__MonkeyConfig_container input:focus,
                .__MonkeyConfig_container textarea:focus,
                .__MonkeyConfig_container select:focus {
                    outline: none;
                    border-color: #667eea;
                    box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
                }

                .__MonkeyConfig_container input[type="checkbox"] {
                    width: 18px;
                    height: 18px;
                    margin: 0;
                    cursor: pointer;
                }

                .__MonkeyConfig_container input[type="color"] {
                    width: 50px;
                    height: 40px;
                    padding: 2px;
                    cursor: pointer;
                }

                .__MonkeyConfig_container input[type="range"] {
                    width: 150px;
                    margin-right: 10px;
                }

                .__MonkeyConfig_range_value {
                    display: inline-block;
                    min-width: 40px;
                    text-align: center;
                    font-weight: 500;
                    color: #667eea;
                }

                .__MonkeyConfig_radio_group {
                    display: flex;
                    flex-direction: column;
                    gap: 8px;
                }

                .__MonkeyConfig_radio_label {
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    cursor: pointer;
                    padding: 4px 0;
                }

                .__MonkeyConfig_radio_label input[type="radio"] {
                    margin: 0;
                }

                .__MonkeyConfig_group {
                    border: 2px solid #e1e5e9;
                    border-radius: 6px;
                    padding: 16px;
                    margin: 8px 0;
                }

                .__MonkeyConfig_group legend {
                    font-weight: 600;
                    color: #333;
                    padding: 0 8px;
                }

                .__MonkeyConfig_custom {
                    padding: 8px 0;
                }

                .__MonkeyConfig_custom_button {
                    background: #f8f9fa;
                    border: 2px solid #e1e5e9;
                    color: #333;
                    padding: 8px 16px;
                    border-radius: 6px;
                    cursor: pointer;
                    transition: all 0.2s ease;
                }

                .__MonkeyConfig_custom_button:hover {
                    background: #e9ecef;
                    border-color: #667eea;
                }

                /* Footer */
                .__MonkeyConfig_footer {
                    padding: 16px 20px;
                    background: #f8f9fa;
                    border-top: 1px solid #e1e5e9;
                    display: flex;
                    gap: 12px;
                    justify-content: flex-end;
                    flex-wrap: wrap;
                }

                .__MonkeyConfig_btn {
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    padding: 10px 16px;
                    border: 2px solid transparent;
                    border-radius: 6px;
                    font-size: 14px;
                    font-weight: 500;
                    cursor: pointer;
                    transition: all 0.2s ease;
                    text-decoration: none;
                }

                .__MonkeyConfig_btn_save {
                    background: #28a745;
                    color: white;
                    border-color: #28a745;
                }

                .__MonkeyConfig_btn_save:hover {
                    background: #218838;
                    transform: translateY(-1px);
                }

                .__MonkeyConfig_btn_reset {
                    background: #dc3545;
                    color: white;
                    border-color: #dc3545;
                }

                .__MonkeyConfig_btn_reset:hover {
                    background: #c82333;
                    transform: translateY(-1px);
                }

                .__MonkeyConfig_btn_reload {
                    background: #007bff;
                    color: white;
                    border-color: #007bff;
                }

                .__MonkeyConfig_btn_reload:hover {
                    background: #0056b3;
                    transform: translateY(-1px);
                }

                .__MonkeyConfig_btn_homepage {
                    background: #6c757d;
                    color: white;
                    border-color: #6c757d;
                }

                .__MonkeyConfig_btn_homepage:hover {
                    background: #545b62;
                    transform: translateY(-1px);
                }

                .__MonkeyConfig_error {
                    color: #dc3545;
                    font-weight: 500;
                    padding: 8px;
                    background: #f8d7da;
                    border: 1px solid #f5c6cb;
                    border-radius: 4px;
                }

                /* Responsive Design */
                @media (max-width: 768px) {
                    .__MonkeyConfig_container {
                        width: 95vw;
                        height: 95vh;
                        margin: 0;
                        transform: translate(-50%, -50%);
                    }

                    .__MonkeyConfig_columns {
                        grid-template-columns: 1fr;
                    }

                    .__MonkeyConfig_footer {
                        flex-direction: column;
                    }

                    .__MonkeyConfig_btn {
                        justify-content: center;
                    }
                }

                /* Dark mode support */
                @media (prefers-color-scheme: dark) {
                    .__MonkeyConfig_container {
                        background: #1a1a1a;
                        border-color: #444;
                        color: #e0e0e0;
                    }

                    .__MonkeyConfig_default_table tr {
                        border-color: #333;
                    }

                    .__MonkeyConfig_container input,
                    .__MonkeyConfig_container textarea,
                    .__MonkeyConfig_container select {
                        background: #2a2a2a;
                        border-color: #444;
                        color: #e0e0e0;
                    }

                    .__MonkeyConfig_footer {
                        background: #2a2a2a;
                        border-color: #444;
                    }

                    .__MonkeyConfig_group {
                        border-color: #444;
                    }

                    .__MonkeyConfig_custom_button {
                        background: #2a2a2a;
                        border-color: #444;
                        color: #e0e0e0;
                    }
                }

                /* Animation */
                @keyframes __MonkeyConfig_fadeIn {
                    from {
                        opacity: 0;
                        transform: translate(-50%, -50%) scale(0.9);
                    }
                    to {
                        opacity: 1;
                        transform: translate(-50%, -50%) scale(1);
                    }
                }
            </style>`;
    }

    /**
     * Clean up all resources
     */
    destroy() {
        try {
            this.close();
            
            this.data = null;
            this.params = null;
            this.values = null;
            this.validationRules.clear();
            this.trustedPolicy = null;
            
            this.log('ModernMonkeyConfig destroyed');
        } catch (error) {
            this.log(`Error during cleanup: ${error.message}`, 'error');
        }
    }
}

// ===========================================
// FACTORY FUNCTION AND EXPORTS
// ===========================================

/**
 * Factory function for creating configuration dialogs
 */
function createMonkeyConfig(configData) {
    try {
        return new ModernMonkeyConfig(configData);
    } catch (error) {
        console.error(`[ModernMonkeyConfig] Failed to create configuration: ${error.message}`);
        return null;
    }
}

// Export for different environments
if (typeof module !== 'undefined' && module.exports) {
    module.exports = ModernMonkeyConfig;
} else if (typeof window !== 'undefined') {
    window.ModernMonkeyConfig = ModernMonkeyConfig;
    window.createMonkeyConfig = createMonkeyConfig;
}

/**
 * Example usage:
 * 
 * const config = createMonkeyConfig({
 *   title: 'My Script Configuration',
 *   menuCommand: true,
 *   buttons: ['save', 'reset', 'close', 'reload'],
 *   parameters: {
 *     enabled: {
 *       type: 'checkbox',
 *       label: 'Enable Script',
 *       default: true
 *     },
 *     maxItems: {
 *       type: 'number',
 *       label: 'Maximum Items',
 *       default: 10,
 *       min: 1,
 *       max: 100
 *     },
 *     theme: {
 *       type: 'select',
 *       label: 'Theme',
 *       choices: {
 *         'light': 'Light Theme',
 *         'dark': 'Dark Theme',
 *         'auto': 'Auto Detect'
 *       },
 *       default: 'auto'
 *     },
 *     opacity: {
 *       type: 'range',
 *       label: 'Opacity',
 *       min: 0.1,
 *       max: 1.0,
 *       step: 0.1,
 *       default: 0.8
 *     },
 *     description: {
 *       type: 'textarea',
 *       label: 'Description',
 *       rows: 4,
 *       cols: 40,
 *       default: ''
 *     }
 *   },
 *   onSave: (values) => {
 *     console.log('Settings saved:', values);
 *     // Apply your settings here
 *   }
 * });
 * 
 * // Usage:
 * config.open();                    // Open configuration dialog
 * const enabled = config.get('enabled');      // Get parameter value
 * config.set('enabled', false);               // Set parameter value
 * config.reset();                             // Reset to defaults
 * config.destroy();                          // Clean up resources
 */
长期地址
遇到问题?请前往 GitHub 提 Issues。