🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

📂 缓存分发状态(共享加速已生效)
🕒 页面同步时间:2026/01/08 03:06:29
🔄 下次更新时间:2026/01/08 04:06:29
手动刷新缓存

Smart Grammar Fixer Pro

Smart grammar fixing with LanguageTool and language detection

As of 2025-11-22. See the latest version.

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

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

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

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

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

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

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

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

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

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

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

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

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

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

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

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name         Smart Grammar Fixer Pro
// @namespace    http://tampermonkey.net/
// @version      6.1
// @description  Smart grammar fixing with LanguageTool and language detection
// @author       You
// @match        *://*/*
// @exclude      https://docs.google.com/*
// @exclude      https://*.office.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        unsafeWindow
// @connect      api.languagetool.org
// @connect      ws.detectlanguage.com
// @antifeature  none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // API Configuration
    const API_CONFIG = {
        languagetool: 'https://api.languagetool.org/v2/check',
        detectlanguage: 'https://ws.detectlanguage.com/0.2/detect'
    };

    // Language Support
    const LANGUAGE_SUPPORT = {
        'en-US': 'English (US)',
        'en-GB': 'English (GB)',
        'ar': 'Arabic',
        'de-DE': 'German',
        'fr-FR': 'French',
        'es-ES': 'Spanish',
        'it-IT': 'Italian',
        'pt-PT': 'Portuguese',
        'pt-BR': 'Portuguese (BR)',
        'nl-NL': 'Dutch',
        'ru-RU': 'Russian',
        'ja-JP': 'Japanese',
        'zh-CN': 'Chinese',
        'ko-KR': 'Korean',
        'pl-PL': 'Polish',
        'sv-SE': 'Swedish',
        'da-DK': 'Danish',
        'fi-FI': 'Finnish',
        'no-NO': 'Norwegian',
        'tr-TR': 'Turkish'
    };

    // Default settings
    const DEFAULT_SETTINGS = {
        // Core Behavior
        enabled: true,
        debugMode: false,

        // API Keys
        apiKeys: {
            detectlanguage: 'a40f80d21131976bdedf653088a12ce0'
        },

        // Language Configuration
        language: {
            main: 'en-US',
            fallback: 'en-US',
            autoDetect: true,
            confidenceThreshold: 0.7,
            forceLanguage: false,
            correctionLanguage: 'auto' // New: Choose language for correction
        },

        // Correction Settings
        correction: {
            autoFixOnSend: true,
            minTextLength: 3,
            maxTextLength: 5000,
            fixPunctuation: true,
            fixCapitalization: true,
            aggressiveCorrection: false
        },

        // User Interface
        ui: {
            showIcons: true,
            showNotifications: true,
            iconPosition: 'top-right',
            iconSize: 'medium',
            darkMode: 'auto',
            animations: true // New: Enable animations
        },

        // Shortcuts
        shortcuts: {
            smartFix: 'Alt+A',
            fixAndSend: 'Alt+Enter',
            quickFix: 'Alt+Q',
            toggleEnabled: 'Alt+Shift+G',
            openSettings: 'Alt+Shift+S'
        },

        // Domain-specific Rules
        domainRules: {
            'gmail.com': { autoFixOnSend: true },
            'outlook.com': { autoFixOnSend: true },
            'twitter.com': { minTextLength: 5 },
            'facebook.com': { minTextLength: 10 },
            'chat.openai.com': { enabled: false },
            'docs.google.com': { enabled: false }
        }
    };

    let settings = JSON.parse(JSON.stringify(DEFAULT_SETTINGS));
    let isProcessing = false;
    let currentDomain = window.location.hostname;

    // Inject styles
    function injectStyles() {
        const styles = `
            .grammar-helper-icon {
                position: absolute;
                width: 24px;
                height: 24px;
                background: #4CAF50;
                color: white;
                border-radius: 50%;
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 11px;
                font-weight: bold;
                cursor: pointer;
                z-index: 10000;
                box-shadow: 0 2px 8px rgba(0,0,0,0.3);
                transition: all 0.3s ease;
                border: 2px solid white;
            }
            .grammar-helper-icon:hover {
                transform: scale(1.2);
                box-shadow: 0 4px 12px rgba(0,0,0,0.4);
            }
            .grammar-language-badge {
                position: absolute;
                top: -5px;
                right: -5px;
                background: #2196F3;
                color: white;
                border-radius: 50%;
                width: 16px;
                height: 16px;
                font-size: 9px;
                display: flex;
                align-items: center;
                justify-content: center;
                border: 1px solid white;
                font-weight: bold;
            }

            /* Enhanced notification animations */
            .grammar-notification {
                position: absolute;
                background: #4CAF50;
                color: white;
                padding: 8px 12px;
                border-radius: 6px;
                font-size: 12px;
                font-family: Arial, sans-serif;
                z-index: 10002;
                box-shadow: 0 4px 12px rgba(0,0,0,0.3);
                max-width: 200px;
                white-space: nowrap;
                transform: translateY(-20px);
                opacity: 0;
            }
            .grammar-notification.error {
                background: #f44336;
            }
            .grammar-notification.warning {
                background: #FF9800;
            }
            .grammar-notification.info {
                background: #2196F3;
            }
            .grammar-notification.processing {
                background: #9C27B0;
            }
            .grammar-notification.success {
                background: #4CAF50;
            }

            /* Animation classes */
            .grammar-notification.show {
                animation: slideInBounce 0.5s ease-out forwards;
            }
            .grammar-notification.hide {
                animation: slideOutUp 0.3s ease-in forwards;
            }

            /* Processing animation */
            .grammar-notification.processing::after {
                content: '';
                position: absolute;
                bottom: 0;
                left: 0;
                height: 3px;
                background: rgba(255,255,255,0.7);
                border-radius: 0 0 6px 6px;
                animation: processingBar 2s linear infinite;
            }

            @keyframes slideInBounce {
                0% {
                    transform: translateY(-20px);
                    opacity: 0;
                }
                60% {
                    transform: translateY(5px);
                    opacity: 1;
                }
                100% {
                    transform: translateY(0);
                    opacity: 1;
                }
            }

            @keyframes slideOutUp {
                0% {
                    transform: translateY(0);
                    opacity: 1;
                }
                100% {
                    transform: translateY(-20px);
                    opacity: 0;
                }
            }

            @keyframes processingBar {
                0% {
                    width: 0%;
                }
                50% {
                    width: 100%;
                }
                100% {
                    width: 0%;
                }
            }

            /* Pulse animation for icon when processing */
            .grammar-helper-icon.processing {
                animation: pulse 1.5s ease-in-out infinite;
            }

            @keyframes pulse {
                0% {
                    transform: scale(1);
                    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
                }
                50% {
                    transform: scale(1.1);
                    box-shadow: 0 4px 16px rgba(76, 175, 80, 0.4);
                }
                100% {
                    transform: scale(1);
                    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
                }
            }

            .grammar-global-notification {
                position: fixed;
                top: 20px;
                right: 20px;
                background: #2196F3;
                color: white;
                padding: 12px 16px;
                border-radius: 8px;
                z-index: 100000;
                box-shadow: 0 4px 12px rgba(0,0,0,0.3);
                font-family: Arial, sans-serif;
                font-size: 14px;
                max-width: 400px;
                word-wrap: break-word;
                transform: translateX(100%);
                transition: transform 0.3s ease;
            }
            .grammar-global-notification.show {
                transform: translateX(0);
            }
            .grammar-global-notification.success {
                background: #4CAF50;
            }
            .grammar-global-notification.error {
                background: #f44336;
            }
            .grammar-global-notification.warning {
                background: #FF9800;
            }
        `;

        const styleSheet = document.createElement('style');
        styleSheet.textContent = styles;
        document.head.appendChild(styleSheet);

        // Inject settings panel styles
        injectSettingsPanelStyles();
    }

    function injectSettingsPanelStyles() {
        const settingsStyles = `
        .grammar-settings-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.7);
            z-index: 99998;
            backdrop-filter: blur(5px);
            animation: fadeIn 0.3s ease;
        }

        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        .grammar-settings-panel {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%) scale(0.9);
            background: white;
            border-radius: 12px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
            z-index: 99999;
            width: 90%;
            max-width: 700px;
            max-height: 90vh;
            overflow: hidden;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            animation: scaleIn 0.3s ease forwards;
        }

        @keyframes scaleIn {
            to {
                transform: translate(-50%, -50%) scale(1);
            }
        }

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

        .grammar-settings-title h2 {
            margin: 0;
            font-size: 1.5em;
            font-weight: 600;
        }

        .grammar-settings-subtitle {
            opacity: 0.9;
            font-size: 0.9em;
            margin-top: 4px;
        }

        .grammar-settings-close {
            background: rgba(255, 255, 255, 0.2);
            border: none;
            color: white;
            font-size: 24px;
            cursor: pointer;
            padding: 0;
            width: 36px;
            height: 36px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background 0.2s ease;
        }

        .grammar-settings-close:hover {
            background: rgba(255, 255, 255, 0.3);
        }

        .grammar-settings-content {
            padding: 24px;
            max-height: 60vh;
            overflow-y: auto;
        }

        .settings-section {
            margin-bottom: 24px;
            animation: slideDown 0.4s ease;
        }

        @keyframes slideDown {
            from {
                opacity: 0;
                transform: translateY(-10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .settings-section h3 {
            margin: 0 0 16px 0;
            font-size: 1.1em;
            color: #495057;
            border-bottom: 1px solid #e9ecef;
            padding-bottom: 8px;
        }

        .settings-row {
            display: flex;
            align-items: center;
            margin-bottom: 12px;
            padding: 8px 0;
        }

        .settings-row label {
            flex: 1;
            margin-right: 16px;
            font-size: 14px;
            color: #495057;
        }

        .settings-row input[type="text"],
        .settings-row input[type="password"],
        .settings-row input[type="number"],
        .settings-row select {
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 14px;
            min-width: 200px;
            transition: border-color 0.2s ease;
        }

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

        .settings-row input[type="checkbox"] {
            margin-right: 8px;
            transform: scale(1.1);
        }

        .shortcut-input {
            background: #f8f9fa !important;
            cursor: pointer;
            min-width: 120px !important;
            text-align: center;
            font-family: monospace;
        }

        .shortcut-input.recording {
            background: #fff3cd !important;
            border-color: #ffc107;
            color: #856404;
        }

        .grammar-settings-footer {
            padding: 20px 24px;
            background: #f8f9fa;
            border-top: 1px solid #e9ecef;
            display: flex;
            justify-content: flex-end;
            gap: 12px;
        }

        .grammar-settings-btn {
            padding: 10px 20px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.2s ease;
        }

        .grammar-settings-btn.primary {
            background: #667eea;
            color: white;
        }

        .grammar-settings-btn.primary:hover {
            background: #5a6fd8;
            transform: translateY(-1px);
        }

        .grammar-settings-btn.secondary {
            background: #6c757d;
            color: white;
        }

        .grammar-settings-btn.secondary:hover {
            background: #5a6268;
            transform: translateY(-1px);
        }

        @media (max-width: 768px) {
            .grammar-settings-panel {
                width: 95%;
                height: 95vh;
            }

            .settings-row {
                flex-direction: column;
                align-items: flex-start;
            }

            .settings-row label {
                margin-bottom: 8px;
                margin-right: 0;
            }
        }
        `;

        const styleSheet = document.createElement('style');
        styleSheet.textContent = settingsStyles;
        document.head.appendChild(styleSheet);
    }

    // Initialize the script
    async function init() {
        try {
            console.log('🔄 Starting Grammar Fixer initialization...');
            await loadSettings();
            applyDomainSpecificRules();
            injectStyles();
            setupGlobalShortcuts();
            setupElementObservers();
            registerMenuCommands();

            console.log('✅ Smart Grammar Fixer Pro initialized successfully');
            console.log('🌐 Current domain:', currentDomain);

            showGlobalNotification('Grammar Fixer Pro ready! Use ' + settings.shortcuts.smartFix + ' to fix grammar.', 'success', 3000);

        } catch (error) {
            console.error('❌ Failed to initialize grammar fixer:', error);
            showGlobalNotification('Grammar fixer failed to initialize', 'error');
        }
    }

    function applyDomainSpecificRules() {
        const domainRule = settings.domainRules[currentDomain];
        if (domainRule) {
            Object.assign(settings, domainRule);
            if (settings.debugMode) {
                console.log('🔧 Applied domain-specific rules for:', currentDomain, domainRule);
            }
        }
    }

    // Settings management
    async function loadSettings() {
        try {
            const savedSettings = await GM_getValue('grammarSettings');
            if (savedSettings) {
                settings = Object.assign({}, DEFAULT_SETTINGS, savedSettings);
            }
        } catch (error) {
            console.error('Error loading settings:', error);
            settings = JSON.parse(JSON.stringify(DEFAULT_SETTINGS));
        }
    }

    async function saveSettings() {
        try {
            await GM_setValue('grammarSettings', settings);
            return true;
        } catch (error) {
            console.error('Error saving settings:', error);
            showGlobalNotification('Failed to save settings', 'error');
            return false;
        }
    }

    // Menu commands
    function registerMenuCommands() {
        GM_registerMenuCommand('⚙️ Grammar Settings', showSettingsPanel);
        GM_registerMenuCommand('🔄 Toggle Enabled', toggleEnabled);
        GM_registerMenuCommand('📊 Status Info', showStatusInfo);
    }

    function toggleEnabled() {
        settings.enabled = !settings.enabled;
        saveSettings();
        showGlobalNotification(`Grammar fixer ${settings.enabled ? 'enabled' : 'disabled'}`);

        if (!settings.enabled) {
            removeAllUIElements();
        } else {
            setTimeout(() => {
                document.querySelectorAll('textarea, input[type="text"], [contenteditable="true"]')
                    .forEach(addSmartIconsToElement);
            }, 1000);
        }
    }

    function showStatusInfo() {
        const status = `
Status: ${settings.enabled ? '✅ Enabled' : '❌ Disabled'}
Domain: ${currentDomain}
Main Language: ${settings.language.main}
Correction Language: ${settings.language.correctionLanguage}
Auto-detect: ${settings.language.autoDetect ? '✅' : '❌'}
Shortcuts: ${Object.values(settings.shortcuts).join(', ')}
        `.trim();

        showGlobalNotification(status, 'info', 5000);
    }

    // Shortcuts
    function setupGlobalShortcuts() {
        document.addEventListener('keydown', function(e) {
            if (!settings.enabled) return;

            const activeEl = document.activeElement;
            if (!isTextElement(activeEl)) return;

            // Smart Fix
            if (checkShortcut(e, settings.shortcuts.smartFix)) {
                e.preventDefault();
                e.stopPropagation();
                handleSmartGrammarFix(activeEl);
            }

            // Fix and Send
            if (checkShortcut(e, settings.shortcuts.fixAndSend)) {
                e.preventDefault();
                e.stopPropagation();
                handleFixAndSend(activeEl);
            }

            // Quick Fix
            if (checkShortcut(e, settings.shortcuts.quickFix)) {
                e.preventDefault();
                e.stopPropagation();
                handleQuickFix(activeEl);
            }

            // Toggle Enabled
            if (checkShortcut(e, settings.shortcuts.toggleEnabled)) {
                e.preventDefault();
                e.stopPropagation();
                toggleEnabled();
            }

            // Open Settings
            if (checkShortcut(e, settings.shortcuts.openSettings)) {
                e.preventDefault();
                e.stopPropagation();
                showSettingsPanel();
            }
        }, true);
    }

    function checkShortcut(event, shortcut) {
        const keys = shortcut.split('+');
        let match = true;

        keys.forEach(key => {
            key = key.trim().toLowerCase();
            if (key === 'alt' && !event.altKey) match = false;
            else if (key === 'ctrl' && !event.ctrlKey) match = false;
            else if (key === 'shift' && !event.shiftKey) match = false;
            else if (key === 'enter' && event.key !== 'Enter') match = false;
            else if (key.length === 1 && event.key.toLowerCase() !== key) match = false;
            else if (key.length > 1 && !['alt', 'ctrl', 'shift', 'enter'].includes(key)) {
                // Handle special keys
                if (key === 'space' && event.key !== ' ') match = false;
                else if (event.key.toLowerCase() !== key) match = false;
            }
        });

        return match;
    }

    function handleQuickFix(element) {
        if (!settings.enabled || isProcessing) return;

        const text = getElementText(element);
        if (text.length < settings.correction.minTextLength) return;

        fixWithLanguageTool(text, settings.language.main)
            .then(fixedText => {
                setElementText(element, fixedText);
                showNotification(element, 'Quick fix applied', 'success');
            })
            .catch(error => {
                console.error('Quick fix error:', error);
                showNotification(element, 'Quick fix failed', 'error');
            });
    }

    // UI Management
    function setupElementObservers() {
        if (!settings.enabled || !settings.ui.showIcons) return;

        // Add to existing elements
        setTimeout(() => {
            document.querySelectorAll('textarea, input[type="text"], input[type="email"], input[type="search"], [contenteditable="true"]')
                .forEach(addSmartIconsToElement);
        }, 1000);

        document.addEventListener('focusin', function(e) {
            if (isTextElement(e.target)) {
                addSmartIconsToElement(e.target);
            }
        });
    }

    function isTextElement(element) {
        return element.tagName === 'TEXTAREA' ||
               (element.tagName === 'INPUT' && (
                   element.type === 'text' ||
                   element.type === 'email' ||
                   element.type === 'search' ||
                   element.type === 'url' ||
                   !element.type
               )) ||
               element.isContentEditable;
    }

    function addSmartIconsToElement(element) {
        if (element._grammarIconsAdded || !settings.ui.showIcons) return;

        const rect = element.getBoundingClientRect();
        if (rect.width === 0 || rect.height === 0) return;

        const icon = document.createElement('div');
        icon.className = 'grammar-helper-icon';
        icon.innerHTML = 'A<div class="grammar-language-badge">LT</div>';
        icon.title = `Fix Grammar (${settings.shortcuts.smartFix})`;

        icon.addEventListener('click', async () => {
            const text = getElementText(element);
            if (text.trim()) {
                await handleSmartGrammarFix(element);
            }
        });

        positionIcon(icon, element);
        document.body.appendChild(icon);

        element._grammarIconsAdded = true;
    }

    function positionIcon(icon, element) {
        const rect = element.getBoundingClientRect();
        const scrollX = window.scrollX || window.pageXOffset;
        const scrollY = window.scrollY || window.pageYOffset;

        const top = rect.top + scrollY - 30;
        const left = rect.right + scrollX - 30;

        icon.style.top = top + 'px';
        icon.style.left = left + 'px';
    }

    function removeAllUIElements() {
        document.querySelectorAll('.grammar-helper-icon, .grammar-notification')
            .forEach(el => el.remove());

        document.querySelectorAll('[class*="grammar"]').forEach(el => {
            if (el._grammarIconsAdded) {
                el._grammarIconsAdded = false;
            }
        });
    }

    // Core Grammar Functions
    async function handleSmartGrammarFix(element) {
        if (isProcessing) {
            showNotification(element, 'Already fixing grammar...', 'warning');
            return;
        }

        isProcessing = true;

        const text = getElementText(element);
        if (!text.trim() || text.length < settings.correction.minTextLength) {
            showNotification(element, 'Text too short to fix', 'warning');
            isProcessing = false;
            return;
        }

        if (text.length > settings.correction.maxTextLength) {
            showNotification(element, 'Text too long to fix', 'warning');
            isProcessing = false;
            return;
        }

        try {
            // Add processing animation to icon
            const icon = element.parentNode?.querySelector('.grammar-helper-icon');
            if (icon && settings.ui.animations) {
                icon.classList.add('processing');
            }

            showNotification(element, 'Fixing grammar...', 'processing');

            let languageCode = settings.language.correctionLanguage;

            // Auto-detect language if set to auto
            if (languageCode === 'auto') {
                if (settings.language.autoDetect && settings.apiKeys.detectlanguage) {
                    try {
                        const detectedLang = await detectLanguage(text);
                        languageCode = detectedLang.code;
                        console.log(`🌍 Detected language: ${detectedLang.name} (${detectedLang.code})`);
                    } catch (error) {
                        console.warn('Language detection failed, using main language:', error);
                        languageCode = settings.language.main;
                    }
                } else {
                    languageCode = settings.language.main;
                }
            }

            const fixedText = await fixWithLanguageTool(text, languageCode);
            setElementText(element, fixedText);

            // Remove processing animation
            if (icon && settings.ui.animations) {
                icon.classList.remove('processing');
            }

            showNotification(element, `Grammar fixed! (${LANGUAGE_SUPPORT[languageCode] || languageCode})`, 'success');

        } catch (error) {
            console.error('Smart grammar fix error:', error);

            // Remove processing animation on error
            const icon = element.parentNode?.querySelector('.grammar-helper-icon');
            if (icon && settings.ui.animations) {
                icon.classList.remove('processing');
            }

            showNotification(element, 'Failed to fix grammar', 'error');
        } finally {
            isProcessing = false;
        }
    }

    async function detectLanguage(text) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'POST',
                url: API_CONFIG.detectlanguage,
                headers: {
                    'Authorization': `Bearer ${settings.apiKeys.detectlanguage}`,
                    'Content-Type': 'application/json'
                },
                data: JSON.stringify({ q: text }),
                timeout: 10000,
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.data && data.data.detections && data.data.detections.length > 0) {
                            const detection = data.data.detections[0];
                            if (detection.confidence >= settings.language.confidenceThreshold) {
                                const langName = LANGUAGE_SUPPORT[detection.language] || detection.language;
                                resolve({
                                    code: detection.language,
                                    name: langName,
                                    confidence: detection.confidence
                                });
                            }
                        }
                        reject('No confident language detection');
                    } catch (e) {
                        reject('Error parsing language detection response: ' + e);
                    }
                },
                onerror: reject,
                ontimeout: () => reject('Language detection timeout')
            });
        });
    }

    async function fixWithLanguageTool(text, languageCode) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'POST',
                url: API_CONFIG.languagetool,
                data: `text=${encodeURIComponent(text)}&language=${languageCode}&enabledOnly=false`,
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                timeout: 15000,
                onload: function(response) {
                    try {
                        if (response.status !== 200) {
                            reject(`LanguageTool API error: ${response.status}`);
                            return;
                        }

                        const result = JSON.parse(response.responseText);
                        let fixedText = text;

                        if (result.matches && result.matches.length > 0) {
                            const matches = result.matches.sort((a, b) => b.offset - a.offset);

                            for (const match of matches) {
                                if (match.replacements && match.replacements.length > 0) {
                                    const replacement = match.replacements[0].value;
                                    const before = fixedText.substring(0, match.offset);
                                    const after = fixedText.substring(match.offset + match.length);
                                    fixedText = before + replacement + after;
                                }
                            }
                        }

                        resolve(fixedText);
                    } catch (e) {
                        reject('Error parsing LanguageTool response: ' + e);
                    }
                },
                onerror: reject,
                ontimeout: () => reject('LanguageTool request timeout')
            });
        });
    }

    async function handleFixAndSend(element) {
        await handleSmartGrammarFix(element);
        if (settings.correction.autoFixOnSend) {
            setTimeout(() => clickSendButton(element), 500);
        }
    }

    function clickSendButton(element) {
        const sendSelectors = [
            'button[type="submit"]', 'input[type="submit"]',
            'button[data-testid*="send"]', 'button[data-testid*="submit"]',
            '[aria-label*="send" i]', '[aria-label*="submit" i]'
        ];

        let sendButton = null;
        const form = element.closest('form');

        if (form) {
            for (const selector of sendSelectors) {
                sendButton = form.querySelector(selector);
                if (sendButton && sendButton.offsetParent !== null) break;
            }
        }

        if (sendButton) {
            sendButton.click();
            return true;
        }

        return false;
    }

    // Utility Functions
    function getElementText(element) {
        if (element.tagName === 'TEXTAREA' || element.tagName === 'INPUT') {
            return element.value;
        } else {
            return element.textContent || element.innerText || '';
        }
    }

    function setElementText(element, text) {
        if (element.tagName === 'TEXTAREA' || element.tagName === 'INPUT') {
            element.value = text;
        } else {
            element.textContent = text;
        }
        element.dispatchEvent(new Event('input', { bubbles: true }));
        element.dispatchEvent(new Event('change', { bubbles: true }));
    }

    function showNotification(element, message, type = 'info') {
        if (!settings.ui.showNotifications) return;

        // Remove existing notification
        const existingNotification = document.querySelector('.grammar-notification');
        if (existingNotification) {
            if (settings.ui.animations) {
                existingNotification.classList.add('hide');
                setTimeout(() => existingNotification.remove(), 300);
            } else {
                existingNotification.remove();
            }
        }

        const notification = document.createElement('div');
        notification.className = `grammar-notification ${type}`;
        notification.textContent = message;

        const rect = element.getBoundingClientRect();
        const scrollX = window.scrollX || window.pageXOffset;
        const scrollY = window.scrollY || window.pageYOffset;

        notification.style.top = (rect.top + scrollY - 40) + 'px';
        notification.style.left = (rect.right + scrollX - 10) + 'px';

        document.body.appendChild(notification);

        // Add show animation
        if (settings.ui.animations) {
            setTimeout(() => {
                notification.classList.add('show');
            }, 10);

            // Auto hide after 3 seconds
            setTimeout(() => {
                notification.classList.add('hide');
                setTimeout(() => {
                    if (notification.parentNode) notification.remove();
                }, 300);
            }, 3000);
        } else {
            // No animation - just remove after 3 seconds
            setTimeout(() => {
                if (notification.parentNode) notification.remove();
            }, 3000);
        }
    }

    function showGlobalNotification(message, type = 'info', duration = 3000) {
        if (!settings.ui.showNotifications) return;

        const notification = document.createElement('div');
        notification.className = `grammar-global-notification ${type}`;
        notification.textContent = message;

        document.body.appendChild(notification);

        if (settings.ui.animations) {
            setTimeout(() => {
                notification.classList.add('show');
            }, 10);

            setTimeout(() => {
                notification.classList.remove('show');
                setTimeout(() => {
                    if (notification.parentNode) notification.remove();
                }, 300);
            }, duration);
        } else {
            setTimeout(() => {
                if (notification.parentNode) notification.remove();
            }, duration);
        }
    }

    // Settings Panel
    function showSettingsPanel() {
        const existingPanel = document.getElementById('grammar-settings-panel');
        if (existingPanel) existingPanel.remove();

        const existingOverlay = document.getElementById('grammar-settings-overlay');
        if (existingOverlay) existingOverlay.remove();

        const overlay = document.createElement('div');
        overlay.id = 'grammar-settings-overlay';
        overlay.className = 'grammar-settings-overlay';

        const panel = document.createElement('div');
        panel.id = 'grammar-settings-panel';
        panel.className = 'grammar-settings-panel';

        panel.innerHTML = `
        <div class="grammar-settings-header">
            <div class="grammar-settings-title">
                <h2>⚙️ Grammar Fixer Settings</h2>
                <div class="grammar-settings-subtitle">LanguageTool + DetectLanguage</div>
            </div>
            <button class="grammar-settings-close" id="settings-close">×</button>
        </div>

        <div class="grammar-settings-content">
            <div class="settings-section">
                <h3>Core Settings</h3>
                <div class="settings-row">
                    <label>
                        <input type="checkbox" id="enabled" ${settings.enabled ? 'checked' : ''}>
                        Enable Grammar Fixer
                    </label>
                </div>
                <div class="settings-row">
                    <label>
                        <input type="checkbox" id="showIcons" ${settings.ui.showIcons ? 'checked' : ''}>
                        Show Helper Icons
                    </label>
                </div>
                <div class="settings-row">
                    <label>
                        <input type="checkbox" id="showNotifications" ${settings.ui.showNotifications ? 'checked' : ''}>
                        Show Notifications
                    </label>
                </div>
                <div class="settings-row">
                    <label>
                        <input type="checkbox" id="animations" ${settings.ui.animations ? 'checked' : ''}>
                        Enable Animations
                    </label>
                </div>
            </div>

            <div class="settings-section">
                <h3>Language Settings</h3>
                <div class="settings-row">
                    <label>Main Language:</label>
                    <select id="mainLanguage">
                        ${Object.entries(LANGUAGE_SUPPORT).map(([code, name]) =>
                            `<option value="${code}" ${settings.language.main === code ? 'selected' : ''}>
                                ${name}
                            </option>`
                        ).join('')}
                    </select>
                </div>
                <div class="settings-row">
                    <label>Correction Language:</label>
                    <select id="correctionLanguage">
                        <option value="auto" ${settings.language.correctionLanguage === 'auto' ? 'selected' : ''}>Auto-detect</option>
                        ${Object.entries(LANGUAGE_SUPPORT).map(([code, name]) =>
                            `<option value="${code}" ${settings.language.correctionLanguage === code ? 'selected' : ''}>
                                ${name}
                            </option>`
                        ).join('')}
                    </select>
                </div>
                <div class="settings-row">
                    <label>
                        <input type="checkbox" id="autoDetect" ${settings.language.autoDetect ? 'checked' : ''}>
                        Auto-detect Language (for auto mode)
                    </label>
                </div>
            </div>

            <div class="settings-section">
                <h3>Keyboard Shortcuts</h3>
                ${Object.entries(settings.shortcuts).map(([action, shortcut]) => `
                <div class="settings-row">
                    <label>${formatActionName(action)}:</label>
                    <input type="text" class="shortcut-input" id="shortcut-${action}" value="${shortcut}" readonly>
                    <button class="grammar-settings-btn secondary change-shortcut" data-action="${action}">Change</button>
                </div>
                `).join('')}
            </div>

            <div class="settings-section">
                <h3>API Configuration</h3>
                <div class="settings-row">
                    <label>DetectLanguage API Key:</label>
                    <input type="password" id="detectlanguageKey" value="${settings.apiKeys.detectlanguage}" placeholder="Enter your API key">
                </div>
                <small>Get free API key from detectlanguage.com</small>
            </div>

            <div class="settings-section">
                <h3>Text Processing</h3>
                <div class="settings-row">
                    <label>Min Text Length:</label>
                    <input type="number" id="minTextLength" value="${settings.correction.minTextLength}" min="1" max="100">
                </div>
                <div class="settings-row">
                    <label>
                        <input type="checkbox" id="autoFixOnSend" ${settings.correction.autoFixOnSend ? 'checked' : ''}>
                        Auto-fix on Send
                    </label>
                </div>
            </div>
        </div>

        <div class="grammar-settings-footer">
            <button class="grammar-settings-btn secondary" id="settings-cancel">Cancel</button>
            <button class="grammar-settings-btn primary" id="settings-save">Save Settings</button>
        </div>
        `;

        // Event listeners
        panel.querySelector('#settings-close').addEventListener('click', closeSettings);
        panel.querySelector('#settings-cancel').addEventListener('click', closeSettings);
        panel.querySelector('#settings-save').addEventListener('click', saveSettingsFromPanel);

        // Shortcut recording
        panel.querySelectorAll('.change-shortcut').forEach(button => {
            button.addEventListener('click', function() {
                const action = this.getAttribute('data-action');
                const input = panel.querySelector(`#shortcut-${action}`);
                startShortcutRecording(input, action);
            });
        });

        overlay.addEventListener('click', closeSettings);

        function closeSettings() {
            if (settings.ui.animations) {
                panel.style.animation = 'scaleIn 0.3s ease reverse';
                overlay.style.animation = 'fadeIn 0.3s ease reverse';
                setTimeout(() => {
                    panel.remove();
                    overlay.remove();
                }, 300);
            } else {
                panel.remove();
                overlay.remove();
            }
        }

        function startShortcutRecording(input, action) {
            input.value = 'Press new shortcut...';
            input.classList.add('recording');

            const handleKeyDown = (e) => {
                e.preventDefault();
                e.stopPropagation();

                // Ignore modifier keys alone
                if (['Alt', 'Control', 'Shift', 'Meta'].includes(e.key)) {
                    return;
                }

                let shortcut = '';
                if (e.altKey) shortcut += 'Alt+';
                if (e.ctrlKey) shortcut += 'Ctrl+';
                if (e.shiftKey) shortcut += 'Shift+';

                if (e.key === ' ') {
                    shortcut += 'Space';
                } else if (e.key === 'Enter') {
                    shortcut += 'Enter';
                } else if (e.key.length === 1) {
                    shortcut += e.key.toUpperCase();
                } else {
                    shortcut += e.key;
                }

                input.value = shortcut;
                input.classList.remove('recording');
                document.removeEventListener('keydown', handleKeyDown);
            };

            document.addEventListener('keydown', handleKeyDown, { once: false });

            // Cancel on escape
            const handleEscape = (e) => {
                if (e.key === 'Escape') {
                    input.value = settings.shortcuts[action];
                    input.classList.remove('recording');
                    document.removeEventListener('keydown', handleKeyDown);
                    document.removeEventListener('keydown', handleEscape);
                }
            };

            document.addEventListener('keydown', handleEscape, { once: true });
        }

        async function saveSettingsFromPanel() {
            settings.enabled = panel.querySelector('#enabled').checked;
            settings.ui.showIcons = panel.querySelector('#showIcons').checked;
            settings.ui.showNotifications = panel.querySelector('#showNotifications').checked;
            settings.ui.animations = panel.querySelector('#animations').checked;
            settings.language.main = panel.querySelector('#mainLanguage').value;
            settings.language.correctionLanguage = panel.querySelector('#correctionLanguage').value;
            settings.language.autoDetect = panel.querySelector('#autoDetect').checked;
            settings.apiKeys.detectlanguage = panel.querySelector('#detectlanguageKey').value;
            settings.correction.minTextLength = parseInt(panel.querySelector('#minTextLength').value);
            settings.correction.autoFixOnSend = panel.querySelector('#autoFixOnSend').checked;

            // Save shortcuts
            Object.keys(settings.shortcuts).forEach(action => {
                const input = panel.querySelector(`#shortcut-${action}`);
                if (input && input.value !== 'Press new shortcut...') {
                    settings.shortcuts[action] = input.value;
                }
            });

            await saveSettings();
            closeSettings();
            showGlobalNotification('Settings saved successfully!', 'success');
        }

        document.body.appendChild(overlay);
        document.body.appendChild(panel);

        // Close on Escape
        document.addEventListener('keydown', function closeOnEscape(e) {
            if (e.key === 'Escape') {
                closeSettings();
                document.removeEventListener('keydown', closeOnEscape);
            }
        });
    }

    function formatActionName(action) {
        return action.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase());
    }

    // Initialize
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    // Global access for debugging
    unsafeWindow.grammarFixer = {
        settings: settings,
        fixText: handleSmartGrammarFix,
        showSettings: showSettingsPanel
    };

})();