MediaWiki

Gadget-CopyTextTool.js:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
创建页面,内容为“// 文本复制工具 (function() { 'use strict'; // ===== 自定义配置区域 ===== const BUTTON_CONFIG = { '蓝色': '{{文本|蓝|', '绿色': '{{文本|绿|', '蓝色下划线': '{{文本|蓝|下划线|', '绿色描边': '{{描边|绿|', '词典': '{{词典|' }; // ======================== let toolElement = null; let isPinned = true; let isDragging = false; let currentX;…”
 
律Rhyme留言 | 贡献
无编辑摘要
 
(未显示同一用户的3个中间版本)
第1行: 第1行:
// 文本复制工具
/**
(function() {
* 文本复制工具 - 修复版
* 支持 MediaWiki 各种编辑器
*/
(function($, mw) {
     'use strict';
     'use strict';
      
      
     // ===== 自定义配置区域 =====
     // ===== 自定义配置 =====
     const BUTTON_CONFIG = {
     var config = {
         '蓝色': '{{文本|蓝|',
         '蓝色': {
         '绿色': '{{文本|绿|',
            template: '{{文本|蓝|{text}}}',
         '蓝色下划线': '{{文本|蓝|下划线|',
            fallback: '{{文本|蓝|'
         '绿色描边': '{{描边|绿|',
        },
         '词典': '{{词典|'
         '绿色': {
            template: '{{文本|绿|{text}}}',
            fallback: '{{文本|绿|'
        },
         '蓝色下划线': {
            template: '{{文本|蓝|下划线|{text}}}',
            fallback: '{{文本|蓝|下划线|'
        },
         '绿色描边': {
            template: '{{描边|绿|{text}}}',
            fallback: '{{描边|绿|'
        },
         '词典': {
            template: '{{词典|{text}}}',
            fallback: '{{词典|'
        },
        '红色': {
            template: '{{文本|红|{text}}}',
            fallback: '{{文本|红|'
        }
    };
   
    var defaultPosition = {
        top: '100px',
        right: '20px'
     };
     };
     // ========================
     // ====================
      
      
     let toolElement = null;
     var toolPanel = null;
     let isPinned = true;
     var floatButton = null;
     let isDragging = false;
     var isVisible = false;
     let currentX;
     var isMinimized = false;
     let currentY;
     var currentMode = 'auto';
     let initialX;
      
     let initialY;
    $(function() {
     let xOffset = 0;
        var savedState = localStorage.getItem('copyTextTool_visible');
    let yOffset = 0;
        isVisible = savedState === 'true';
       
        createFloatButton();
        createToolPanel();
       
        if (isVisible) {
            showTool();
        }
     });
      
    function createFloatButton() {
        floatButton = $('<div>')
            .attr('id', 'copy-tool-fab')
            .attr('title', '文本复制工具')
            .html('📋')
            .css({
                position: 'fixed',
                bottom: '30px',
                right: '30px',
                width: '56px',
                height: '56px',
                borderRadius: '50%',
                background: 'linear-gradient(135deg, #2196F3 0%, #1976D2 100%)',
                color: 'white',
                fontSize: '24px',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                cursor: 'pointer',
                boxShadow: '0 4px 12px rgba(33, 150, 243, 0.4)',
                zIndex: 9998,
                transition: 'all 0.3s ease',
                userSelect: 'none'
            })
            .on('click', toggleTool)
            .hover(
                function() {
                    $(this).css({
                        transform: 'scale(1.1)',
                        boxShadow: '0 6px 16px rgba(33, 150, 243, 0.6)'
                    });
                },
                function() {
                    $(this).css({
                        transform: 'scale(1)',
                        boxShadow: '0 4px 12px rgba(33, 150, 243, 0.4)'
                    });
                }
            )
            .appendTo('body');
    }
      
      
    // 创建工具面板
     function createToolPanel() {
     function createToolPanel() {
         const tool = document.createElement('div');
         var savedPos = localStorage.getItem('copyTextTool_position');
         tool.id = 'copy-text-tool';
         var position = savedPos ? JSON.parse(savedPos) : defaultPosition;
         tool.innerHTML = `
       
             <div class="tool-header" id="tool-header">
        toolPanel = $('<div>')
                 <span class="tool-title">📋 文本复制工具</span>
            .attr('id', 'copy-text-tool')
                <div class="tool-controls">
            .css({
                    <button class="tool-btn" id="minimize-btn" title="最小化">−</button>
                position: 'fixed',
                    <button class="tool-btn" id="close-btn" title="关闭">×</button>
                top: position.top,
                 </div>
                right: position.right,
             </div>
                left: position.left || 'auto',
             <div class="tool-body">
                width: '340px',
                 <div class="pin-control">
                background: 'white',
                     <input type="checkbox" id="pin-checkbox" ${isPinned ? 'checked' : ''}>
                border: '2px solid #2196F3',
                     <label for="pin-checkbox">窗口置顶</label>
                borderRadius: '12px',
                 </div>
                boxShadow: '0 8px 24px rgba(0,0,0,0.15)',
                 <div id="button-container"></div>
                zIndex: 9999,
                 <div class="tool-status" id="tool-status">准备就绪</div>
                display: 'none',
             </div>
                fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
         `;
            });
          
        var header = $('<div>')
             .attr('id', 'tool-header')
            .css({
                background: 'linear-gradient(135deg, #2196F3 0%, #1976D2 100%)',
                color: 'white',
                padding: '12px 15px',
                borderRadius: '10px 10px 0 0',
                cursor: 'move',
                display: 'flex',
                justifyContent: 'space-between',
                alignItems: 'center',
                userSelect: 'none'
            })
            .appendTo(toolPanel);
       
        $('<div>')
            .css({
                fontWeight: 'bold',
                 fontSize: '15px',
                display: 'flex',
                alignItems: 'center',
                gap: '8px'
            })
            .html('<span style="font-size: 18px">📋</span> 文本工具')
            .appendTo(header);
       
        var controls = $('<div>')
            .css({
                display: 'flex',
                gap: '8px'
            })
            .appendTo(header);
       
        $('<button>')
            .attr('title', '最小化')
            .html('')
            .css({
                background: 'rgba(255,255,255,0.2)',
                border: 'none',
                color: 'white',
                width: '24px',
                height: '24px',
                borderRadius: '4px',
                cursor: 'pointer',
                fontSize: '16px'
            })
            .on('click', minimizeTool)
            .hover(
                function() { $(this).css('background', 'rgba(255,255,255,0.3)'); },
                function() { $(this).css('background', 'rgba(255,255,255,0.2)'); }
            )
            .appendTo(controls);
       
        $('<button>')
            .attr('title', '关闭')
            .html('×')
            .css({
                background: 'rgba(255,255,255,0.2)',
                border: 'none',
                color: 'white',
                width: '24px',
                height: '24px',
                borderRadius: '4px',
                cursor: 'pointer',
                fontSize: '20px'
            })
            .on('click', hideTool)
            .hover(
                function() { $(this).css('background', 'rgba(255,255,255,0.3)'); },
                function() { $(this).css('background', 'rgba(255,255,255,0.2)'); }
            )
            .appendTo(controls);
       
        var body = $('<div>')
            .attr('id', 'tool-body')
            .css({
                 padding: '15px'
            })
            .appendTo(toolPanel);
       
        // 模式选择
        var modeSelector = $('<div>')
            .css({
                display: 'flex',
                gap: '8px',
                marginBottom: '12px',
                padding: '8px',
                background: '#f5f5f5',
                borderRadius: '6px'
            })
             .appendTo(body);
       
        $('<div>')
            .text('模式:')
            .css({
                fontSize: '13px',
                color: '#666',
                lineHeight: '28px',
                fontWeight: '500'
            })
            .appendTo(modeSelector);
       
        var modes = [
            { id: 'auto', name: '智能', title: '自动检测' },
            { id: 'insert', name: '插入', title: '插入到编辑器' },
             { id: 'copy', name: '复制', title: '复制到剪贴板' }
        ];
       
        var modeButtons = $('<div>')
            .css({
                display: 'flex',
                gap: '4px',
                 flex: '1'
            })
            .appendTo(modeSelector);
       
        modes.forEach(function(mode) {
            $('<button>')
                .attr({
                    'data-mode': mode.id,
                    'title': mode.title
                })
                .text(mode.name)
                .css({
                    flex: '1',
                    padding: '6px 8px',
                     background: mode.id === 'auto' ? '#2196F3' : 'white',
                    color: mode.id === 'auto' ? 'white' : '#666',
                    border: '1px solid #ddd',
                    borderRadius: '4px',
                    cursor: 'pointer',
                    fontSize: '12px',
                    transition: 'all 0.2s'
                })
                .on('click', function() {
                    currentMode = mode.id;
                    modeButtons.find('button').css({
                        background: 'white',
                        color: '#666'
                    });
                    $(this).css({
                        background: '#2196F3',
                        color: 'white'
                    });
                     updateStatus('✓ 切换到' + mode.name + '模式', true);
                })
                .appendTo(modeButtons);
        });
       
        // 按钮容器
        var buttonContainer = $('<div>')
            .css({
                display: 'grid',
                 gridTemplateColumns: 'repeat(2, 1fr)',
                gap: '8px',
                marginBottom: '10px'
            })
            .appendTo(body);
       
        $.each(config, function(name, conf) {
            $('<button>')
                .text(name)
                .css({
                    padding: '12px 8px',
                    background: '#2196F3',
                    color: 'white',
                    border: 'none',
                    borderRadius: '6px',
                    cursor: 'pointer',
                    fontSize: '13px',
                    fontWeight: '500',
                    transition: 'all 0.2s ease'
                })
                .on('click', function() {
                    handleButtonClick(name, conf);
                })
                .hover(
                    function() {
                        $(this).css({
                            background: '#1976D2',
                            transform: 'translateY(-1px)',
                            boxShadow: '0 2px 8px rgba(33, 150, 243, 0.3)'
                        });
                    },
                    function() {
                        $(this).css({
                            background: '#2196F3',
                            transform: 'translateY(0)',
                            boxShadow: 'none'
                        });
                    }
                )
                 .appendTo(buttonContainer);
        });
       
        $('<div>')
            .attr('id', 'copy-status')
            .css({
                textAlign: 'center',
                color: '#666',
                padding: '10px',
                fontSize: '12px',
                minHeight: '20px',
                background: '#f9f9f9',
                borderRadius: '6px'
            })
            .html('💡 先选中文字,再点击按钮')
            .appendTo(body);
       
        toolPanel.appendTo('body');
        makeDraggable(toolPanel[0], header[0]);
    }
   
    // ===== 核心功能:处理按钮点击 =====
    function handleButtonClick(name, conf) {
        console.log('[文本工具] 按钮点击:', name);
       
        // 获取选中文字
        var selectedText = getSelectedText();
        console.log('[文本工具] 选中文字:', selectedText);
       
        // 决定使用什么文本
        var finalText = selectedText ?
            conf.template.replace('{text}', selectedText) :
            conf.fallback;
       
        console.log('[文本工具] 最终文本:', finalText);
       
        // 根据模式决定操作
        if (currentMode === 'copy') {
            // 强制复制模式
            copyToClipboard(finalText);
            updateStatus('✓ 已复制: ' + name, true);
            return;
        }
       
        // 尝试插入
        var editor = findEditor();
        console.log('[文本工具] 找到的编辑器:', editor);
       
        if (editor && currentMode !== 'copy') {
            // 找到编辑器,执行插入
            var success = insertToEditor(editor, finalText, selectedText ? true : false);
            if (success) {
                updateStatus('✓ 已插入: ' + name, true);
            } else {
                // 插入失败,回退到复制
                copyToClipboard(finalText);
                updateStatus('⚠ 插入失败,已复制', false);
            }
        } else {
            // 未找到编辑器或处于复制模式
            copyToClipboard(finalText);
            updateStatus('✓ 已复制: ' + name, true);
        }
    }
   
    // ===== 查找编辑器 =====
    function findEditor() {
        // 1. 检查 wpTextbox1 (MediaWiki 标准编辑器)
        var wpTextbox = document.getElementById('wpTextbox1');
        if (wpTextbox) {
            console.log('[文本工具] 找到 wpTextbox1');
            return { type: 'textarea', element: wpTextbox };
        }
       
        // 2. 检查 CodeMirror
        if (typeof $ !== 'undefined' && $('.CodeMirror').length > 0) {
            var cm = $('.CodeMirror')[0];
            if (cm.CodeMirror) {
                 console.log('[文本工具] 找到 CodeMirror');
                return { type: 'codemirror', element: cm.CodeMirror };
            }
        }
       
        // 3. 检查当前焦点元素
        var activeEl = document.activeElement;
        if (activeEl && (activeEl.tagName === 'TEXTAREA' ||
            (activeEl.tagName === 'INPUT' && activeEl.type === 'text'))) {
            console.log('[文本工具] 找到活动输入框:', activeEl.tagName);
            return { type: 'textarea', element: activeEl };
        }
       
        // 4. 检查可编辑元素
        if (activeEl && activeEl.contentEditable === 'true') {
            console.log('[文本工具] 找到可编辑元素');
             return { type: 'contenteditable', element: activeEl };
        }
       
        console.log('[文本工具] 未找到编辑器');
        return null;
    }
   
    // ===== 获取选中文字 =====
    function getSelectedText() {
        // 1. 先检查编辑器内的选中
        var editor = findEditor();
         if (editor) {
            if (editor.type === 'textarea') {
                var el = editor.element;
                var start = el.selectionStart;
                var end = el.selectionEnd;
                if (start !== end) {
                    return el.value.substring(start, end);
                }
            } else if (editor.type === 'codemirror') {
                var selection = editor.element.getSelection();
                if (selection) {
                    return selection;
                }
            }
        }
          
          
         // 添加按钮
         // 2. 检查页面上的选中文字
         const buttonContainer = tool.querySelector('#button-container');
         var selection = window.getSelection();
         for (const [name, text] of Object.entries(BUTTON_CONFIG)) {
        if (selection && selection.toString().trim()) {
            const button = document.createElement('button');
            return selection.toString().trim();
             button.className = 'copy-button';
        }
            button.textContent = name;
       
             button.onclick = () => copyText(text, name);
        return '';
             buttonContainer.appendChild(button);
    }
   
    // ===== 插入到编辑器 =====
    function insertToEditor(editor, text, replaceSelection) {
         console.log('[文本工具] 执行插入:', editor.type, text, replaceSelection);
       
        try {
            if (editor.type === 'textarea') {
                var el = editor.element;
                var start = el.selectionStart;
                var end = el.selectionEnd;
                var value = el.value;
               
                if (replaceSelection && start !== end) {
                    // 替换选中的文本
                    el.value = value.substring(0, start) + text + value.substring(end);
                    var newPos = start + text.length;
                    el.selectionStart = el.selectionEnd = newPos;
                } else {
                    // 在光标位置插入
                    el.value = value.substring(0, start) + text + value.substring(start);
                    var newPos = start + text.length;
                    el.selectionStart = el.selectionEnd = newPos;
                }
               
                // 触发事件
                var event = new Event('input', { bubbles: true });
                el.dispatchEvent(event);
               
                // 聚焦
                el.focus();
                console.log('[文本工具] 插入成功 (textarea)');
                return true;
               
             } else if (editor.type === 'codemirror') {
                var cm = editor.element;
                if (replaceSelection) {
                    cm.replaceSelection(text);
                } else {
                    var cursor = cm.getCursor();
                    cm.replaceRange(text, cursor);
                }
                cm.focus();
                console.log('[文本工具] 插入成功 (codemirror)');
                return true;
               
             } else if (editor.type === 'contenteditable') {
                document.execCommand('insertText', false, text);
                console.log('[文本工具] 插入成功 (contenteditable)');
                return true;
            }
        } catch (e) {
             console.error('[文本工具] 插入失败:', e);
            return false;
         }
         }
          
          
        document.body.appendChild(tool);
         return false;
         return tool;
     }
     }
      
      
     // 复制文本到剪贴板
     // ===== 复制到剪贴板 =====
     function copyText(text, buttonName) {
     function copyToClipboard(text) {
         // 使用现代剪贴板API
        console.log('[文本工具] 复制到剪贴板:', text);
          
         if (navigator.clipboard && navigator.clipboard.writeText) {
         if (navigator.clipboard && navigator.clipboard.writeText) {
             navigator.clipboard.writeText(text).then(() => {
             navigator.clipboard.writeText(text).then(function() {
                 showStatus(`✓ 已复制: ${buttonName}`, true);
                 console.log('[文本工具] 复制成功 (现代API)');
             }).catch(() => {
             }).catch(function(err) {
                 fallbackCopy(text, buttonName);
                console.log('[文本工具] 现代API失败,使用备用方法');
                 fallbackCopy(text);
             });
             });
         } else {
         } else {
             fallbackCopy(text, buttonName);
             fallbackCopy(text);
         }
         }
     }
     }
      
      
    // 备用复制方法
     function fallbackCopy(text) {
     function fallbackCopy(text, buttonName) {
         var $temp = $('<textarea>')
         const textarea = document.createElement('textarea');
            .val(text)
        textarea.value = text;
            .css({
        textarea.style.position = 'fixed';
                position: 'fixed',
        textarea.style.opacity = '0';
                opacity: 0,
         document.body.appendChild(textarea);
                top: '-9999px',
         textarea.select();
                left: '-9999px'
            })
            .appendTo('body');
          
        $temp[0].select();
         $temp[0].setSelectionRange(0, 99999);
       
         try {
         try {
             document.execCommand('copy');
             var success = document.execCommand('copy');
             showStatus(`✓ 已复制: ${buttonName}`, true);
             console.log('[文本工具] 复制', success ? '成功' : '失败', '(备用方法)');
         } catch (err) {
         } catch(err) {
             showStatus('复制失败', false);
             console.error('[文本工具] 复制失败:', err);
         }
         }
         document.body.removeChild(textarea);
          
        $temp.remove();
     }
     }
      
      
     // 显示状态
     // ===== 状态更新 =====
     function showStatus(message, success) {
     function updateStatus(message, success) {
         const status = document.getElementById('tool-status');
         console.log('[文本工具] 状态:', message);
         status.textContent = message;
          
         status.className = 'tool-status' + (success ? ' success' : '');
        var icon = success ? '✓' : '⚠';
        var color = success ? '#2196F3' : '#ff9800';
       
        $('#copy-status')
            .html('<b>' + icon + '</b> ' + message)
            .css({
                color: color,
                fontWeight: 'bold'
            });
          
        setTimeout(function() {
            $('#copy-status')
                .html('💡 先选中文字,再点击按钮')
                .css({
                    color: '#666',
                    fontWeight: 'normal'
                });
        }, 3000);
     }
     }
      
      
     // 拖拽功能
     // ===== UI 控制 =====
     function dragStart(e) {
     function toggleTool() {
         if (e.type === "touchstart") {
         if (isVisible) {
             initialX = e.touches[0].clientX - xOffset;
             hideTool();
            initialY = e.touches[0].clientY - yOffset;
         } else {
         } else {
             initialX = e.clientX - xOffset;
             showTool();
            initialY = e.clientY - yOffset;
        }
       
        if (e.target.id === "tool-header" || e.target.className === "tool-title") {
            isDragging = true;
         }
         }
     }
     }
      
      
     function drag(e) {
     function showTool() {
         if (isDragging) {
         if (isMinimized) {
             e.preventDefault();
             isMinimized = false;
              
             $('#tool-body').show();
            if (e.type === "touchmove") {
             toolPanel.css('width', '340px');
                currentX = e.touches[0].clientX - initialX;
                currentY = e.touches[0].clientY - initialY;
             } else {
                currentX = e.clientX - initialX;
                currentY = e.clientY - initialY;
            }
           
            xOffset = currentX;
            yOffset = currentY;
           
            setTranslate(currentX, currentY, toolElement);
         }
         }
        toolPanel.fadeIn(200);
        isVisible = true;
        localStorage.setItem('copyTextTool_visible', 'true');
     }
     }
      
      
     function dragEnd(e) {
     function hideTool() {
         initialX = currentX;
         toolPanel.fadeOut(200);
         initialY = currentY;
         isVisible = false;
         isDragging = false;
         localStorage.setItem('copyTextTool_visible', 'false');
     }
     }
      
      
     function setTranslate(xPos, yPos, el) {
     function minimizeTool() {
         el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`;
         if (isMinimized) {
            $('#tool-body').slideDown(200);
            toolPanel.css('width', '340px');
            isMinimized = false;
        } else {
            $('#tool-body').slideUp(200);
            toolPanel.css('width', 'auto');
            isMinimized = true;
        }
     }
     }
      
      
     // 初始化
     // ===== 拖动功能 =====
     function init() {
     function makeDraggable(element, handle) {
         // 添加菜单项
         var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
         mw.util.addPortletLink(
       
             'p-tb',
         handle.onmousedown = dragMouseDown;
             '#',
       
             '📋 文本复制工具',
        function dragMouseDown(e) {
             't-copy-text-tool',
             e = e || window.event;
             '打开文本复制工具',
             e.preventDefault();
             null,
             pos3 = e.clientX;
            '#t-permalink'
             pos4 = e.clientY;
         );
             document.onmouseup = closeDragElement;
             document.onmousemove = elementDrag;
         }
          
          
         // 点击菜单项显示工具
         function elementDrag(e) {
        document.getElementById('t-copy-text-tool').addEventListener('click', function(e) {
            e = e || window.event;
             e.preventDefault();
             e.preventDefault();
             if (!toolElement) {
             pos1 = pos3 - e.clientX;
                toolElement = createToolPanel();
            pos2 = pos4 - e.clientY;
               
            pos3 = e.clientX;
                // 绑定事件
            pos4 = e.clientY;
                const header = document.getElementById('tool-header');
           
                header.addEventListener('mousedown', dragStart);
            var newTop = (element.offsetTop - pos2);
                document.addEventListener('mousemove', drag);
            var newLeft = (element.offsetLeft - pos1);
                document.addEventListener('mouseup', dragEnd);
           
               
            element.style.top = newTop + "px";
                // 最小化按钮
            element.style.left = newLeft + "px";
                document.getElementById('minimize-btn').onclick = () => {
            element.style.right = "auto";
                    toolElement.classList.toggle('minimized');
        }
                };
       
               
        function closeDragElement() {
                // 关闭按钮
            document.onmouseup = null;
                document.getElementById('close-btn').onclick = () => {
            document.onmousemove = null;
                    toolElement.remove();
           
                    toolElement = null;
             var position = {
                };
                 top: element.style.top,
               
                left: element.style.left
                // 置顶开关
            };
                document.getElementById('pin-checkbox').onchange = (e) => {
            localStorage.setItem('copyTextTool_position', JSON.stringify(position));
                    isPinned = e.target.checked;
         }
                    toolElement.style.position = isPinned ? 'fixed' : 'absolute';
                };
             } else {
                 toolElement.style.display = toolElement.style.display === 'none' ? 'block' : 'none';
            }
         });
     }
     }
      
      
    // 页面加载完成后初始化
})(jQuery, mediaWiki);
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();

2025年10月3日 (五) 21:06的最新版本

/**
 * 文本复制工具 - 修复版
 * 支持 MediaWiki 各种编辑器
 */
(function($, mw) {
    'use strict';
    
    // ===== 自定义配置 =====
    var config = {
        '蓝色': {
            template: '{{文本|蓝|{text}}}',
            fallback: '{{文本|蓝|'
        },
        '绿色': {
            template: '{{文本|绿|{text}}}',
            fallback: '{{文本|绿|'
        },
        '蓝色下划线': {
            template: '{{文本|蓝|下划线|{text}}}',
            fallback: '{{文本|蓝|下划线|'
        },
        '绿色描边': {
            template: '{{描边|绿|{text}}}',
            fallback: '{{描边|绿|'
        },
        '词典': {
            template: '{{词典|{text}}}',
            fallback: '{{词典|'
        },
        '红色': {
            template: '{{文本|红|{text}}}',
            fallback: '{{文本|红|'
        }
    };
    
    var defaultPosition = {
        top: '100px',
        right: '20px'
    };
    // ====================
    
    var toolPanel = null;
    var floatButton = null;
    var isVisible = false;
    var isMinimized = false;
    var currentMode = 'auto';
    
    $(function() {
        var savedState = localStorage.getItem('copyTextTool_visible');
        isVisible = savedState === 'true';
        
        createFloatButton();
        createToolPanel();
        
        if (isVisible) {
            showTool();
        }
    });
    
    function createFloatButton() {
        floatButton = $('<div>')
            .attr('id', 'copy-tool-fab')
            .attr('title', '文本复制工具')
            .html('📋')
            .css({
                position: 'fixed',
                bottom: '30px',
                right: '30px',
                width: '56px',
                height: '56px',
                borderRadius: '50%',
                background: 'linear-gradient(135deg, #2196F3 0%, #1976D2 100%)',
                color: 'white',
                fontSize: '24px',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                cursor: 'pointer',
                boxShadow: '0 4px 12px rgba(33, 150, 243, 0.4)',
                zIndex: 9998,
                transition: 'all 0.3s ease',
                userSelect: 'none'
            })
            .on('click', toggleTool)
            .hover(
                function() {
                    $(this).css({
                        transform: 'scale(1.1)',
                        boxShadow: '0 6px 16px rgba(33, 150, 243, 0.6)'
                    });
                },
                function() {
                    $(this).css({
                        transform: 'scale(1)',
                        boxShadow: '0 4px 12px rgba(33, 150, 243, 0.4)'
                    });
                }
            )
            .appendTo('body');
    }
    
    function createToolPanel() {
        var savedPos = localStorage.getItem('copyTextTool_position');
        var position = savedPos ? JSON.parse(savedPos) : defaultPosition;
        
        toolPanel = $('<div>')
            .attr('id', 'copy-text-tool')
            .css({
                position: 'fixed',
                top: position.top,
                right: position.right,
                left: position.left || 'auto',
                width: '340px',
                background: 'white',
                border: '2px solid #2196F3',
                borderRadius: '12px',
                boxShadow: '0 8px 24px rgba(0,0,0,0.15)',
                zIndex: 9999,
                display: 'none',
                fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
            });
        
        var header = $('<div>')
            .attr('id', 'tool-header')
            .css({
                background: 'linear-gradient(135deg, #2196F3 0%, #1976D2 100%)',
                color: 'white',
                padding: '12px 15px',
                borderRadius: '10px 10px 0 0',
                cursor: 'move',
                display: 'flex',
                justifyContent: 'space-between',
                alignItems: 'center',
                userSelect: 'none'
            })
            .appendTo(toolPanel);
        
        $('<div>')
            .css({
                fontWeight: 'bold',
                fontSize: '15px',
                display: 'flex',
                alignItems: 'center',
                gap: '8px'
            })
            .html('<span style="font-size: 18px">📋</span> 文本工具')
            .appendTo(header);
        
        var controls = $('<div>')
            .css({
                display: 'flex',
                gap: '8px'
            })
            .appendTo(header);
        
        $('<button>')
            .attr('title', '最小化')
            .html('−')
            .css({
                background: 'rgba(255,255,255,0.2)',
                border: 'none',
                color: 'white',
                width: '24px',
                height: '24px',
                borderRadius: '4px',
                cursor: 'pointer',
                fontSize: '16px'
            })
            .on('click', minimizeTool)
            .hover(
                function() { $(this).css('background', 'rgba(255,255,255,0.3)'); },
                function() { $(this).css('background', 'rgba(255,255,255,0.2)'); }
            )
            .appendTo(controls);
        
        $('<button>')
            .attr('title', '关闭')
            .html('×')
            .css({
                background: 'rgba(255,255,255,0.2)',
                border: 'none',
                color: 'white',
                width: '24px',
                height: '24px',
                borderRadius: '4px',
                cursor: 'pointer',
                fontSize: '20px'
            })
            .on('click', hideTool)
            .hover(
                function() { $(this).css('background', 'rgba(255,255,255,0.3)'); },
                function() { $(this).css('background', 'rgba(255,255,255,0.2)'); }
            )
            .appendTo(controls);
        
        var body = $('<div>')
            .attr('id', 'tool-body')
            .css({
                padding: '15px'
            })
            .appendTo(toolPanel);
        
        // 模式选择
        var modeSelector = $('<div>')
            .css({
                display: 'flex',
                gap: '8px',
                marginBottom: '12px',
                padding: '8px',
                background: '#f5f5f5',
                borderRadius: '6px'
            })
            .appendTo(body);
        
        $('<div>')
            .text('模式:')
            .css({
                fontSize: '13px',
                color: '#666',
                lineHeight: '28px',
                fontWeight: '500'
            })
            .appendTo(modeSelector);
        
        var modes = [
            { id: 'auto', name: '智能', title: '自动检测' },
            { id: 'insert', name: '插入', title: '插入到编辑器' },
            { id: 'copy', name: '复制', title: '复制到剪贴板' }
        ];
        
        var modeButtons = $('<div>')
            .css({
                display: 'flex',
                gap: '4px',
                flex: '1'
            })
            .appendTo(modeSelector);
        
        modes.forEach(function(mode) {
            $('<button>')
                .attr({
                    'data-mode': mode.id,
                    'title': mode.title
                })
                .text(mode.name)
                .css({
                    flex: '1',
                    padding: '6px 8px',
                    background: mode.id === 'auto' ? '#2196F3' : 'white',
                    color: mode.id === 'auto' ? 'white' : '#666',
                    border: '1px solid #ddd',
                    borderRadius: '4px',
                    cursor: 'pointer',
                    fontSize: '12px',
                    transition: 'all 0.2s'
                })
                .on('click', function() {
                    currentMode = mode.id;
                    modeButtons.find('button').css({
                        background: 'white',
                        color: '#666'
                    });
                    $(this).css({
                        background: '#2196F3',
                        color: 'white'
                    });
                    updateStatus('✓ 切换到' + mode.name + '模式', true);
                })
                .appendTo(modeButtons);
        });
        
        // 按钮容器
        var buttonContainer = $('<div>')
            .css({
                display: 'grid',
                gridTemplateColumns: 'repeat(2, 1fr)',
                gap: '8px',
                marginBottom: '10px'
            })
            .appendTo(body);
        
        $.each(config, function(name, conf) {
            $('<button>')
                .text(name)
                .css({
                    padding: '12px 8px',
                    background: '#2196F3',
                    color: 'white',
                    border: 'none',
                    borderRadius: '6px',
                    cursor: 'pointer',
                    fontSize: '13px',
                    fontWeight: '500',
                    transition: 'all 0.2s ease'
                })
                .on('click', function() {
                    handleButtonClick(name, conf);
                })
                .hover(
                    function() {
                        $(this).css({
                            background: '#1976D2',
                            transform: 'translateY(-1px)',
                            boxShadow: '0 2px 8px rgba(33, 150, 243, 0.3)'
                        });
                    },
                    function() {
                        $(this).css({
                            background: '#2196F3',
                            transform: 'translateY(0)',
                            boxShadow: 'none'
                        });
                    }
                )
                .appendTo(buttonContainer);
        });
        
        $('<div>')
            .attr('id', 'copy-status')
            .css({
                textAlign: 'center',
                color: '#666',
                padding: '10px',
                fontSize: '12px',
                minHeight: '20px',
                background: '#f9f9f9',
                borderRadius: '6px'
            })
            .html('💡 先选中文字,再点击按钮')
            .appendTo(body);
        
        toolPanel.appendTo('body');
        makeDraggable(toolPanel[0], header[0]);
    }
    
    // ===== 核心功能:处理按钮点击 =====
    function handleButtonClick(name, conf) {
        console.log('[文本工具] 按钮点击:', name);
        
        // 获取选中文字
        var selectedText = getSelectedText();
        console.log('[文本工具] 选中文字:', selectedText);
        
        // 决定使用什么文本
        var finalText = selectedText ? 
            conf.template.replace('{text}', selectedText) : 
            conf.fallback;
        
        console.log('[文本工具] 最终文本:', finalText);
        
        // 根据模式决定操作
        if (currentMode === 'copy') {
            // 强制复制模式
            copyToClipboard(finalText);
            updateStatus('✓ 已复制: ' + name, true);
            return;
        }
        
        // 尝试插入
        var editor = findEditor();
        console.log('[文本工具] 找到的编辑器:', editor);
        
        if (editor && currentMode !== 'copy') {
            // 找到编辑器,执行插入
            var success = insertToEditor(editor, finalText, selectedText ? true : false);
            if (success) {
                updateStatus('✓ 已插入: ' + name, true);
            } else {
                // 插入失败,回退到复制
                copyToClipboard(finalText);
                updateStatus('⚠ 插入失败,已复制', false);
            }
        } else {
            // 未找到编辑器或处于复制模式
            copyToClipboard(finalText);
            updateStatus('✓ 已复制: ' + name, true);
        }
    }
    
    // ===== 查找编辑器 =====
    function findEditor() {
        // 1. 检查 wpTextbox1 (MediaWiki 标准编辑器)
        var wpTextbox = document.getElementById('wpTextbox1');
        if (wpTextbox) {
            console.log('[文本工具] 找到 wpTextbox1');
            return { type: 'textarea', element: wpTextbox };
        }
        
        // 2. 检查 CodeMirror
        if (typeof $ !== 'undefined' && $('.CodeMirror').length > 0) {
            var cm = $('.CodeMirror')[0];
            if (cm.CodeMirror) {
                console.log('[文本工具] 找到 CodeMirror');
                return { type: 'codemirror', element: cm.CodeMirror };
            }
        }
        
        // 3. 检查当前焦点元素
        var activeEl = document.activeElement;
        if (activeEl && (activeEl.tagName === 'TEXTAREA' || 
            (activeEl.tagName === 'INPUT' && activeEl.type === 'text'))) {
            console.log('[文本工具] 找到活动输入框:', activeEl.tagName);
            return { type: 'textarea', element: activeEl };
        }
        
        // 4. 检查可编辑元素
        if (activeEl && activeEl.contentEditable === 'true') {
            console.log('[文本工具] 找到可编辑元素');
            return { type: 'contenteditable', element: activeEl };
        }
        
        console.log('[文本工具] 未找到编辑器');
        return null;
    }
    
    // ===== 获取选中文字 =====
    function getSelectedText() {
        // 1. 先检查编辑器内的选中
        var editor = findEditor();
        if (editor) {
            if (editor.type === 'textarea') {
                var el = editor.element;
                var start = el.selectionStart;
                var end = el.selectionEnd;
                if (start !== end) {
                    return el.value.substring(start, end);
                }
            } else if (editor.type === 'codemirror') {
                var selection = editor.element.getSelection();
                if (selection) {
                    return selection;
                }
            }
        }
        
        // 2. 检查页面上的选中文字
        var selection = window.getSelection();
        if (selection && selection.toString().trim()) {
            return selection.toString().trim();
        }
        
        return '';
    }
    
    // ===== 插入到编辑器 =====
    function insertToEditor(editor, text, replaceSelection) {
        console.log('[文本工具] 执行插入:', editor.type, text, replaceSelection);
        
        try {
            if (editor.type === 'textarea') {
                var el = editor.element;
                var start = el.selectionStart;
                var end = el.selectionEnd;
                var value = el.value;
                
                if (replaceSelection && start !== end) {
                    // 替换选中的文本
                    el.value = value.substring(0, start) + text + value.substring(end);
                    var newPos = start + text.length;
                    el.selectionStart = el.selectionEnd = newPos;
                } else {
                    // 在光标位置插入
                    el.value = value.substring(0, start) + text + value.substring(start);
                    var newPos = start + text.length;
                    el.selectionStart = el.selectionEnd = newPos;
                }
                
                // 触发事件
                var event = new Event('input', { bubbles: true });
                el.dispatchEvent(event);
                
                // 聚焦
                el.focus();
                console.log('[文本工具] 插入成功 (textarea)');
                return true;
                
            } else if (editor.type === 'codemirror') {
                var cm = editor.element;
                if (replaceSelection) {
                    cm.replaceSelection(text);
                } else {
                    var cursor = cm.getCursor();
                    cm.replaceRange(text, cursor);
                }
                cm.focus();
                console.log('[文本工具] 插入成功 (codemirror)');
                return true;
                
            } else if (editor.type === 'contenteditable') {
                document.execCommand('insertText', false, text);
                console.log('[文本工具] 插入成功 (contenteditable)');
                return true;
            }
        } catch (e) {
            console.error('[文本工具] 插入失败:', e);
            return false;
        }
        
        return false;
    }
    
    // ===== 复制到剪贴板 =====
    function copyToClipboard(text) {
        console.log('[文本工具] 复制到剪贴板:', text);
        
        if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard.writeText(text).then(function() {
                console.log('[文本工具] 复制成功 (现代API)');
            }).catch(function(err) {
                console.log('[文本工具] 现代API失败,使用备用方法');
                fallbackCopy(text);
            });
        } else {
            fallbackCopy(text);
        }
    }
    
    function fallbackCopy(text) {
        var $temp = $('<textarea>')
            .val(text)
            .css({
                position: 'fixed',
                opacity: 0,
                top: '-9999px',
                left: '-9999px'
            })
            .appendTo('body');
        
        $temp[0].select();
        $temp[0].setSelectionRange(0, 99999);
        
        try {
            var success = document.execCommand('copy');
            console.log('[文本工具] 复制', success ? '成功' : '失败', '(备用方法)');
        } catch(err) {
            console.error('[文本工具] 复制失败:', err);
        }
        
        $temp.remove();
    }
    
    // ===== 状态更新 =====
    function updateStatus(message, success) {
        console.log('[文本工具] 状态:', message);
        
        var icon = success ? '✓' : '⚠';
        var color = success ? '#2196F3' : '#ff9800';
        
        $('#copy-status')
            .html('<b>' + icon + '</b> ' + message)
            .css({
                color: color,
                fontWeight: 'bold'
            });
        
        setTimeout(function() {
            $('#copy-status')
                .html('💡 先选中文字,再点击按钮')
                .css({
                    color: '#666',
                    fontWeight: 'normal'
                });
        }, 3000);
    }
    
    // ===== UI 控制 =====
    function toggleTool() {
        if (isVisible) {
            hideTool();
        } else {
            showTool();
        }
    }
    
    function showTool() {
        if (isMinimized) {
            isMinimized = false;
            $('#tool-body').show();
            toolPanel.css('width', '340px');
        }
        toolPanel.fadeIn(200);
        isVisible = true;
        localStorage.setItem('copyTextTool_visible', 'true');
    }
    
    function hideTool() {
        toolPanel.fadeOut(200);
        isVisible = false;
        localStorage.setItem('copyTextTool_visible', 'false');
    }
    
    function minimizeTool() {
        if (isMinimized) {
            $('#tool-body').slideDown(200);
            toolPanel.css('width', '340px');
            isMinimized = false;
        } else {
            $('#tool-body').slideUp(200);
            toolPanel.css('width', 'auto');
            isMinimized = true;
        }
    }
    
    // ===== 拖动功能 =====
    function makeDraggable(element, handle) {
        var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        
        handle.onmousedown = dragMouseDown;
        
        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }
        
        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            
            var newTop = (element.offsetTop - pos2);
            var newLeft = (element.offsetLeft - pos1);
            
            element.style.top = newTop + "px";
            element.style.left = newLeft + "px";
            element.style.right = "auto";
        }
        
        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
            
            var position = {
                top: element.style.top,
                left: element.style.left
            };
            localStorage.setItem('copyTextTool_position', JSON.stringify(position));
        }
    }
    
})(jQuery, mediaWiki);