个人待办事项清单

浏览器右下角的个人待办事项清单,支持多个清单管理,可双击编辑项目,右键菜单修改清单名称

// ==UserScript==
// @name         个人待办事项清单
// @namespace    http://tampermonkey.net/
// @version      0.42
// @description  浏览器右下角的个人待办事项清单,支持多个清单管理,可双击编辑项目,右键菜单修改清单名称
// @author       Your Name
// @match        *://*/*
// @license MIT
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    // 获取用户主题设置
    let userThemePreference = GM_getValue('todo-theme-preference', 'auto');

    // 检测是否为暗色模式
    function isDarkMode() {
        // 如果用户选择了特定主题,则直接返回
        if (userThemePreference === 'dark') return true;
        if (userThemePreference === 'light') return false;

        // 自动模式下,检测系统偏好
        if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
            return true;
        }

        // 检测网站暗色模式 - 通过检查背景颜色
        const bodyBg = window.getComputedStyle(document.body).backgroundColor;
        if (bodyBg) {
            const rgb = bodyBg.match(/\d+/g);
            if (rgb && rgb.length >= 3) {
                const brightness = (0.299 * parseInt(rgb[0]) + 0.587 * parseInt(rgb[1]) + 0.114 * parseInt(rgb[2])) / 255;
                return brightness < 0.5;
            }
        }

        // 检查是否有常见的暗色模式类
        return document.documentElement.classList.contains('dark') ||
               document.body.classList.contains('dark-mode') ||
               document.body.classList.contains('darkmode') ||
               document.body.classList.contains('dark-theme');
    }

    // 设置当前模式
    let darkMode = isDarkMode();

    // 获取主题颜色
    function getThemeColors(isDark) {
        // 通用颜色属性
        const baseColors = {
            btnBg: '#3498db',
            btnBgHover: '#2980b9',
            danger: isDark ? '#e74c3c' : '#ff6b6b'
        };

        // 特定主题颜色
        const themeSpecific = isDark ? {
            // 暗色模式颜色
            bg: '#2c2c2c',
            textPrimary: '#e0e0e0',
            textSecondary: '#a0a0a0',
            panelBg: '#333333',
            headerBg: '#2c3e50',
            itemBg: '#3a3a3a',
            itemBgHover: '#444444',
            itemBorder: '#484848',
            inputBg: '#444444',
            inputBorder: '#555555',
            listItemsBg: '#2a2a2a',
            borderColor: 'rgba(255,255,255,0.1)'
        } : {
            // 亮色模式颜色
            bg: 'white',
            textPrimary: '#333333',
            textSecondary: '#666666',
            panelBg: 'white',
            headerBg: '#3498db',
            itemBg: '#f5f5f5',
            itemBgHover: '#e8e8e8',
            itemBorder: '#f1f1f1',
            inputBg: 'white',
            inputBorder: '#ddd',
            listItemsBg: '#fafafa',
            borderColor: '#eee'
        };

        // 合并并返回所有颜色属性
        return {...baseColors, ...themeSpecific};
    }

    // 样式定义 - 根据当前模式使用不同的颜色变量
    let colors = getThemeColors(darkMode);

    // 获取定义好的CSS样式
    function getStyles(colors) {
        return `
            #todo-button {
                position: fixed;
                top: 50%;
                right: 0;
                transform: translateY(-50%);
                width: 32px;
                height: 32px;
                background-color: ${colors.btnBg};
                border-radius: 50% 0 0 50%;
                display: flex;
                justify-content: center;
                align-items: center;
                color: white;
                font-size: 16px;
                cursor: pointer;
                z-index: 9999;
                box-shadow: 0 2px 5px rgba(0,0,0,0.3);
                transition: all 0.3s;
            }

            #todo-button:hover {
                transform: translateY(-50%) translateX(-5px);
                background-color: ${colors.btnBgHover};
            }

            #todo-panel {
                position: fixed;
                bottom: 80px;
                right: 20px;
                width: 250px;
                max-height: 450px;
                background-color: ${colors.panelBg};
                border-radius: 8px;
                z-index: 9998;
                box-shadow: 0 2px 10px rgba(0,0,0,0.3);
                display: none;
                flex-direction: column;
                overflow: hidden;
                border: 1px solid ${colors.itemBorder};
                transition: background-color 0.3s;
            }

            #todo-header {
                padding: 10px;
                background-color: ${colors.headerBg};
                color: white;
                font-weight: bold;
                font-size: 14px;
                display: flex;
                justify-content: center;
                align-items: center;
                text-align: center;
                transition: background-color 0.3s;
            }

            #todo-content {
                padding: 12px;
                overflow-y: auto;
                max-height: 400px;
                color: ${colors.textPrimary};
                transition: color 0.3s;
            }

            .todo-list-button {
                display: flex;
                align-items: center;
                justify-content: space-between;
                width: 100%;
                padding: 8px 10px;
                margin-bottom: 6px;
                background-color: ${colors.itemBg};
                border: none;
                border-radius: 4px;
                text-align: left;
                cursor: pointer;
                transition: all 0.2s;
                font-size: 14px;
                color: ${colors.textPrimary};
            }

            .todo-list-button:hover {
                background-color: ${colors.itemBgHover};
            }

            .todo-list-items {
                margin-top: 8px;
                margin-bottom: 15px;
                display: none;
                background-color: ${colors.listItemsBg};
                border-radius: 4px;
                padding: 5px;
                transition: background-color 0.3s;
            }

            .todo-item {
                display: flex;
                align-items: center;
                padding: 6px 8px;
                border-bottom: 1px solid ${colors.itemBorder};
                user-select: none;
                transition: border-color 0.3s;
            }

            .todo-item input[type="checkbox"] {
                margin-right: 8px;
                min-width: 16px;
                min-height: 16px;
            }

            .todo-item span {
                flex-grow: 1;
                max-width: 180px;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                font-size: 14px;
                color: ${colors.textPrimary};
                transition: color 0.3s;
            }

            .todo-item button {
                background: none;
                border: none;
                color: ${colors.danger};
                cursor: pointer;
                margin-left: 5px;
                font-size: 16px;
                opacity: 0.5;
                transition: opacity 0.2s, color 0.3s;
            }

            .todo-item:hover button {
                opacity: 1;
            }

            .todo-items-container {
                margin-bottom: 10px;
                max-height: 250px;
                overflow-y: auto;
            }

            .add-item-form, #add-list-form {
                display: flex;
                margin-top: 8px;
                margin-bottom: 10px;
            }

            .add-item-form input, #add-list-form input {
                flex-grow: 1;
                padding: 6px 8px;
                border: 1px solid ${colors.inputBorder};
                background-color: ${colors.inputBg};
                color: ${colors.textPrimary};
                border-radius: 4px 0 0 4px;
                font-size: 13px;
                height: 16px;
                line-height: 16px;
                box-sizing: content-box;
                transition: border-color 0.3s, background-color 0.3s, color 0.3s;
            }

            .add-item-form button, #add-list-form button, .action-button {
                padding: 6px 10px;
                background-color: ${colors.btnBg};
                color: white;
                border: none;
                border-radius: 0 4px 4px 0;
                cursor: pointer;
                transition: background-color 0.3s;
            }

            .completed {
                text-decoration: line-through;
                color: ${colors.textSecondary};
                transition: color 0.3s;
            }

            .action-buttons {
                display: flex;
                gap: 8px;
                margin-top: 15px;
            }

            .action-button {
                flex: 1;
                border-radius: 4px;
                font-size: 12px;
            }

            .action-button:hover, .add-item-form button:hover, #add-list-form button:hover {
                background-color: ${colors.btnBgHover};
            }

            .delete-list-button {
                margin-top: 10px;
                padding: 6px;
                background-color: ${colors.danger};
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                width: 100%;
                transition: all 0.2s;
                font-size: 13px;
            }

            .delete-list-button:hover {
                background-color: ${darkMode ? '#c0392b' : '#ff4f4f'};
            }

            .list-count {
                margin-left: 8px;
                background-color: ${colors.btnBg};
                color: white;
                border-radius: 10px;
                padding: 2px 6px;
                font-size: 11px;
                min-width: 18px;
                text-align: center;
                transition: background-color 0.3s;
            }

            #theme-toggle {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-top: 15px;
                padding: 10px;
                background-color: ${colors.itemBg};
                border-radius: 4px;
                transition: background-color 0.3s;
            }

            #theme-toggle span {
                font-size: 13px;
                color: ${colors.textPrimary};
                transition: color 0.3s;
            }

            #theme-toggle select {
                padding: 4px 8px;
                border-radius: 4px;
                border: 1px solid ${colors.inputBorder};
                background-color: ${colors.inputBg};
                color: ${colors.textPrimary};
                font-size: 13px;
                transition: border-color 0.3s, background-color 0.3s, color 0.3s;
            }

            .context-menu {
                position: fixed;
                background-color: ${colors.panelBg};
                border-radius: 8px;
                box-shadow: 0 4px 15px rgba(0,0,0,0.15);
                padding: 8px 0;
                z-index: 10000;
                display: none;
                min-width: 200px;
                max-width: 280px;
                border: 1px solid ${colors.borderColor};
                opacity: 0;
                transform: translateY(10px);
                transition: opacity 0.2s, transform 0.2s, background-color 0.3s, border-color 0.3s;
            }

            .context-menu.visible {
                opacity: 1;
                transform: translateY(0);
            }

            .context-menu button {
                display: flex;
                align-items: center;
                width: 100%;
                padding: 10px 15px;
                text-align: left;
                background: none;
                border: none;
                cursor: pointer;
                font-size: 14px;
                color: ${colors.textPrimary};
                transition: background-color 0.2s, color 0.3s;
                position: relative;
                overflow: hidden;
                white-space: nowrap;
                text-overflow: ellipsis;
            }

            .context-menu button:hover {
                background-color: ${colors.itemBgHover};
            }

            .context-menu-title {
                padding: 5px 15px 8px;
                margin-top: -5px;
                color: ${colors.textSecondary};
                font-size: 12px;
                border-bottom: 1px solid ${colors.borderColor};
                margin-bottom: 5px;
                transition: color 0.3s, border-color 0.3s;
            }

            .menu-icon {
                margin-right: 10px;
                font-size: 16px;
                color: ${colors.textSecondary};
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 20px;
                transition: color 0.3s;
            }

            .title-text {
                overflow: hidden;
                text-overflow: ellipsis;
                max-width: 180px;
                white-space: nowrap;
                display: inline-block;
            }

            /* 编辑模式的样式 */
            .todo-item.editing span {
                display: none;
            }

            .edit-input {
                flex-grow: 1;
                padding: 2px 4px;
                margin-right: 5px;
                border: 1px solid ${colors.inputBorder};
                background-color: ${colors.inputBg};
                color: ${colors.textPrimary};
                border-radius: 4px;
                font-size: 13px;
                height: 16px;
                line-height: 16px;
                box-sizing: content-box;
                display: none;
            }

            .todo-item.editing .edit-input {
                display: block;
            }

            /* 修改列表名称时的样式 */
            .list-edit-input {
                width: 100%;
                padding: 6px 8px;
                border: 1px solid ${colors.inputBorder};
                background-color: ${colors.inputBg};
                color: ${colors.textPrimary};
                border-radius: 4px;
                font-size: 14px;
                box-sizing: border-box;
                margin-bottom: 8px;
            }
        `;
    }

    // 应用当前主题样式
    let styleElement = GM_addStyle(getStyles(colors));

    // 数据存储和获取
    const todoData = GM_getValue('todo-lists', {});

    // 当前打开的清单名称
    let currentOpenedListName = null;

    // 全局元素引用
    let globalElements;

    // 通用函数:阻止事件冒泡
    function stopPropagation(e) {
        if (e) e.stopPropagation();
    }

    // 通用的添加事项函数(适用于添加清单和添加待办项)
    function handleAddFormSubmit(inputElement, submitHandler, e) {
        stopPropagation(e);
        const text = inputElement.value.trim();
        if (text) {
            submitHandler(text);
            inputElement.value = '';
            inputElement.focus();
        }
    }

    // 创建DOM元素
    function createElements() {
        // 创建主按钮
        const todoButton = document.createElement('div');
        todoButton.id = 'todo-button';
        todoButton.innerHTML = '✓';
        todoButton.title = '待办事项';
        document.body.appendChild(todoButton);

        // 创建面板
        const todoPanel = document.createElement('div');
        todoPanel.id = 'todo-panel';

        // 头部
        const todoHeader = document.createElement('div');
        todoHeader.id = 'todo-header';
        todoHeader.innerHTML = '待办事项清单';

        // 内容区域
        const todoContent = document.createElement('div');
        todoContent.id = 'todo-content';

        // 添加到面板
        todoPanel.appendChild(todoHeader);
        todoPanel.appendChild(todoContent);
        document.body.appendChild(todoPanel);

        // 创建右键菜单
        const contextMenu = document.createElement('div');
        contextMenu.className = 'context-menu';
        document.body.appendChild(contextMenu);

        return {
            button: todoButton,
            panel: todoPanel,
            content: todoContent,
            contextMenu: contextMenu
        };
    }

    // 初始化事件
    function initEvents(elements) {
        // 点击按钮显示面板
        elements.button.addEventListener('click', function(e) {
            elements.panel.style.display = elements.panel.style.display === 'flex' ? 'none' : 'flex';
            stopPropagation(e);

            // 如果显示面板,则更新内容
            if (elements.panel.style.display === 'flex') {
                updatePanelContent(elements);
            }
        });

        // 点击页面其他地方关闭面板和菜单
        document.addEventListener('click', function(e) {
            if (e.target.closest('#todo-panel') || e.target.closest('#todo-button')) {
                return;
            }

            // 关闭面板和菜单
            elements.panel.style.display = 'none';

            // 添加菜单渐隐效果
            if (elements.contextMenu.style.display === 'block') {
                elements.contextMenu.classList.remove('visible');
                setTimeout(() => {
                    elements.contextMenu.style.display = 'none';
                }, 200);
            } else {
                elements.contextMenu.style.display = 'none';
            }
        });

        // 阻止面板点击事件冒泡
        elements.panel.addEventListener('click', stopPropagation);

        // 右键点击主按钮
        elements.button.addEventListener('contextmenu', function(e) {
            e.preventDefault();

            // 检查是否有清单
            const lists = Object.keys(todoData);
            if (lists.length === 0) {
                return; // 没有清单时不显示
            }

            // 获取按钮位置以便显示菜单
            const buttonRect = elements.button.getBoundingClientRect();

            // 显示右键菜单在按钮的左侧
            elements.contextMenu.style.display = 'block';
            elements.contextMenu.style.left = (buttonRect.left - elements.contextMenu.offsetWidth - 10) + 'px';
            elements.contextMenu.style.top = (buttonRect.top + buttonRect.height/2 - elements.contextMenu.offsetHeight/2) + 'px';

            // 清除旧菜单项
            elements.contextMenu.innerHTML = '';

            // 添加菜单标题
            const menuTitle = document.createElement('div');
            menuTitle.className = 'context-menu-title';
            menuTitle.innerHTML = '我的待办清单';
            elements.contextMenu.appendChild(menuTitle);

            // 添加清单到菜单
            lists.forEach(listName => {
                const menuItem = document.createElement('button');

                // 添加图标和文本容器
                const iconSpan = document.createElement('span');
                iconSpan.className = 'menu-icon';
                iconSpan.innerHTML = '📝';
                menuItem.appendChild(iconSpan);

                // 添加文本和省略号支持
                const textSpan = document.createElement('span');
                textSpan.className = 'title-text';
                textSpan.textContent = listName;
                menuItem.appendChild(textSpan);

                // 添加未完成项目计数
                const list = todoData[listName] || [];
                const uncompletedCount = list.filter(item => !item.completed).length;
                if (uncompletedCount > 0) {
                    const countSpan = document.createElement('span');
                    countSpan.className = 'list-count';
                    countSpan.textContent = uncompletedCount;
                    menuItem.appendChild(countSpan);
                }

                // 点击清单按钮事件
                menuItem.addEventListener('click', function(evt) {
                    stopPropagation(evt); // 阻止事件冒泡
                    openList(listName);
                    elements.panel.style.display = 'flex';
                    elements.contextMenu.style.display = 'none';
                    elements.contextMenu.classList.remove('visible');
                });
                elements.contextMenu.appendChild(menuItem);
            });

            // 添加动画效果
            setTimeout(() => {
                elements.contextMenu.classList.add('visible');
            }, 10);

            stopPropagation(e);
        });
    }

    // 更新面板内容
    function updatePanelContent(elements) {
        const content = elements.content;
        content.innerHTML = '';

        // 获取所有清单
        const lists = Object.keys(todoData);

        if (lists.length === 0) {
            // 如果没有清单,显示欢迎信息
            content.innerHTML = `<p style="color: ${colors.textSecondary}; font-size: 13px; text-align: center;">欢迎使用待办事项清单!<br>请创建您的第一个清单。</p>`;
        } else {
            // 显示所有清单
            lists.forEach(listName => {
                // 创建清单按钮
                const listButton = document.createElement('button');
                listButton.className = 'todo-list-button';

                // 添加文本容器
                const textSpan = document.createElement('span');
                textSpan.textContent = listName;
                listButton.appendChild(textSpan);

                // 添加未完成项目计数
                const list = todoData[listName] || [];
                const uncompletedCount = list.filter(item => !item.completed).length;
                if (uncompletedCount > 0) {
                    const countSpan = document.createElement('span');
                    countSpan.className = 'list-count';
                    countSpan.textContent = uncompletedCount;
                    listButton.appendChild(countSpan);
                }

                content.appendChild(listButton);

                // 创建清单内容区域
                const listItems = document.createElement('div');
                listItems.className = 'todo-list-items';
                listItems.setAttribute('data-list', listName);
                content.appendChild(listItems);

                // 清单按钮点击事件
                listButton.addEventListener('click', function(e) {
                    e.stopPropagation(); // 阻止事件冒泡
                    toggleListItems(listName);
                });

                // 清单按钮右键点击事件
                listButton.addEventListener('contextmenu', function(e) {
                    e.preventDefault();
                    e.stopPropagation();

                    // 显示右键菜单
                    showListContextMenu(e, listName, elements);
                });
            });
        }

        // 添加新清单表单
        const addListForm = document.createElement('div');
        addListForm.id = 'add-list-form';
        addListForm.innerHTML = `
            <input type="text" placeholder="新建清单名称" />
            <button>添加</button>
        `;
        content.appendChild(addListForm);

        // 添加清单按钮事件
        const addListButton = addListForm.querySelector('button');
        const addListInput = addListForm.querySelector('input');

        // 添加新清单的处理函数
        function submitNewList(listName) {
            if (!todoData[listName]) {
                todoData[listName] = [];
                GM_setValue('todo-lists', todoData);
                updatePanelContent(elements);

                // 确保面板保持打开状态
                elements.panel.style.display = 'flex';
            }
        }

        // 点击添加按钮
        addListButton.addEventListener('click', e => handleAddFormSubmit(addListInput, submitNewList, e));

        // 按下回车键
        addListInput.addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                handleAddFormSubmit(addListInput, submitNewList, e);
                e.preventDefault();
            }
        });

        // 添加导入导出按钮
        const actionButtons = document.createElement('div');
        actionButtons.className = 'action-buttons';

        // 导出按钮
        const exportButton = document.createElement('button');
        exportButton.className = 'action-button';
        exportButton.textContent = '导出数据';
        exportButton.addEventListener('click', exportData);
        actionButtons.appendChild(exportButton);

        // 导入按钮
        const importButton = document.createElement('button');
        importButton.className = 'action-button';
        importButton.textContent = '导入数据';
        importButton.addEventListener('click', importData);
        actionButtons.appendChild(importButton);

        content.appendChild(actionButtons);

        // 添加主题切换控件
        const themeToggle = document.createElement('div');
        themeToggle.id = 'theme-toggle';

        const themeLabel = document.createElement('span');
        themeLabel.textContent = '主题设置:';
        themeToggle.appendChild(themeLabel);

        const themeSelect = document.createElement('select');
        const options = [
            { value: 'auto', text: '自动 (跟随系统/网站)' },
            { value: 'light', text: '亮色模式' },
            { value: 'dark', text: '暗色模式' }
        ];

        options.forEach(option => {
            const optionEl = document.createElement('option');
            optionEl.value = option.value;
            optionEl.textContent = option.text;
            optionEl.selected = userThemePreference === option.value;
            themeSelect.appendChild(optionEl);
        });

        themeSelect.addEventListener('change', function() {
            userThemePreference = this.value;
            GM_setValue('todo-theme-preference', userThemePreference);

            // 更新主题
            darkMode = userThemePreference === 'dark' ||
                     (userThemePreference === 'auto' && isDarkMode());

            // 更新颜色方案和样式
            colors = getThemeColors(darkMode);
            styleElement.innerHTML = getStyles(colors);

            // 更新内容
            updatePanelContentKeepingState();
        });

        themeToggle.appendChild(themeSelect);
        content.appendChild(themeToggle);

        // 阻止表单和按钮事件冒泡
        addListForm.addEventListener('click', e => e.stopPropagation());
        actionButtons.addEventListener('click', e => e.stopPropagation());
    }

    // 导出数据
    function exportData() {
        const dataStr = JSON.stringify(todoData);
        const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);

        const exportFileDefaultName = 'todo-data.json';

        const linkElement = document.createElement('a');
        linkElement.setAttribute('href', dataUri);
        linkElement.setAttribute('download', exportFileDefaultName);
        linkElement.click();
    }

    // 导入数据
    function importData() {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.json';

        input.onchange = e => {
            const file = e.target.files[0];

            if (!file) return;

            const reader = new FileReader();

            reader.onload = event => {
                try {
                    const importedData = JSON.parse(event.target.result);

                    // 验证导入的数据结构
                    if (typeof importedData === 'object') {
                        // 确认导入
                        if (confirm('确定要导入数据吗?这将覆盖当前的所有待办清单。')) {
                            Object.assign(todoData, importedData);
                            GM_setValue('todo-lists', todoData);
                            updatePanelContent(globalElements);
                            alert('数据导入成功!');
                        }
                    } else {
                        alert('无效的数据格式!');
                    }
                } catch (error) {
                    alert('导入失败:' + error.message);
                }
            };

            reader.readAsText(file);
        };

        input.click();
    }

    // 切换显示/隐藏清单内容
    function toggleListItems(listName) {
        const allListItems = document.querySelectorAll('.todo-list-items');
        allListItems.forEach(item => {
            if (item.getAttribute('data-list') === listName) {
                const isDisplayed = item.style.display === 'block';
                item.style.display = isDisplayed ? 'none' : 'block';

                // 如果显示,则更新内容并保存当前打开的清单名称
                if (!isDisplayed) {
                    updateListItems(item, listName);
                    currentOpenedListName = listName;
                } else {
                    currentOpenedListName = null;
                }
            } else {
                item.style.display = 'none';
            }
        });
    }

    // 直接打开指定清单(用于右键菜单)
    function openList(listName) {
        const allListItems = document.querySelectorAll('.todo-list-items');
        allListItems.forEach(item => {
            const isTarget = item.getAttribute('data-list') === listName;
            item.style.display = isTarget ? 'block' : 'none';

            if (isTarget) {
                updateListItems(item, listName);
                currentOpenedListName = listName;
            }
        });
    }

    // 更新清单项目
    function updateListItems(container, listName) {
        // 保存滚动位置 - 从 itemsContainer 获取
        const itemsContainer = container.querySelector('.todo-items-container');
        const scrollTop = itemsContainer ? itemsContainer.scrollTop : 0;

        container.innerHTML = '';

        // 获取清单中的所有项目
        let items = todoData[listName] || [];

        // 将已完成的项目排序到底部
        items.sort((a, b) => {
            if (a.completed === b.completed) {
                // 如果完成状态相同,按照创建时间排序
                return a.createdAt - b.createdAt;
            }
            // 完成的排在未完成的后面
            return a.completed ? 1 : -1;
        });

        // 创建待办事项列表容器
        const newItemsContainer = document.createElement('div');
        newItemsContainer.className = 'todo-items-container';
        container.appendChild(newItemsContainer);

        // 添加现有项目
        items.forEach((item, index) => {
            const itemElement = document.createElement('div');
            itemElement.className = 'todo-item';
            itemElement.setAttribute('data-index', index);

            // 复选框
            const checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            checkbox.checked = item.completed;
            itemElement.appendChild(checkbox);

            // 文本
            const span = document.createElement('span');
            span.textContent = item.text;
            if (item.completed) {
                span.className = 'completed';
            }
            itemElement.appendChild(span);

            // 添加编辑输入框(默认隐藏)
            const editInput = document.createElement('input');
            editInput.type = 'text';
            editInput.className = 'edit-input';
            editInput.value = item.text;
            itemElement.appendChild(editInput);

            // 删除按钮
            const deleteButton = document.createElement('button');
            deleteButton.innerHTML = '×';
            itemElement.appendChild(deleteButton);

            newItemsContainer.appendChild(itemElement);

            // 复选框事件
            checkbox.addEventListener('change', function() {
                todoData[listName][index].completed = checkbox.checked;
                GM_setValue('todo-lists', todoData);
                span.className = checkbox.checked ? 'completed' : '';

                // 记住这个清单是打开的并更新面板(会重排序项目)
                currentOpenedListName = listName;
                updatePanelContentKeepingState();
            });

            // 双击编辑功能
            span.addEventListener('dblclick', function(e) {
                stopPropagation(e);
                itemElement.classList.add('editing');
                editInput.focus();
                editInput.select();
            });

            // 编辑输入框失去焦点时保存
            editInput.addEventListener('blur', function() {
                finishEditing();
            });

            // 按下回车键保存
            editInput.addEventListener('keypress', function(e) {
                if (e.key === 'Enter') {
                    finishEditing();
                    e.preventDefault();
                }
            });

            // 按下ESC键取消
            editInput.addEventListener('keydown', function(e) {
                if (e.key === 'Escape') {
                    editInput.value = item.text; // 恢复原值
                    itemElement.classList.remove('editing');
                    e.preventDefault();
                }
            });

            // 完成编辑的函数
            function finishEditing() {
                const newText = editInput.value.trim();
                if (newText && newText !== item.text) {
                    todoData[listName][index].text = newText;
                    GM_setValue('todo-lists', todoData);
                    span.textContent = newText;
                }
                itemElement.classList.remove('editing');
            }

            // 删除按钮事件
            deleteButton.addEventListener('click', function(e) {
                stopPropagation(e);

                todoData[listName].splice(index, 1);
                GM_setValue('todo-lists', todoData);

                // 记住这个清单是打开的并更新面板
                currentOpenedListName = listName;
                updatePanelContentKeepingState();
            });

            // 阻止项目元素事件冒泡
            itemElement.addEventListener('click', stopPropagation);
        });

        // 添加项目表单
        const addItemForm = document.createElement('div');
        addItemForm.className = 'add-item-form';
        addItemForm.innerHTML = `
            <input type="text" placeholder="添加新待办事项" />
            <button>添加</button>
        `;
        container.appendChild(addItemForm);

        // 添加待办事项按钮事件
        const addItemButton = addItemForm.querySelector('button');
        const addItemInput = addItemForm.querySelector('input');

        // 自动聚焦输入框
        setTimeout(() => addItemInput.focus(), 10);

        // 阻止表单事件冒泡
        addItemForm.addEventListener('click', stopPropagation);

        // 添加新待办事项的处理函数
        function submitNewItem(itemText) {
            todoData[listName].push({
                text: itemText,
                completed: false,
                createdAt: new Date().getTime()
            });
            GM_setValue('todo-lists', todoData);

            currentOpenedListName = listName;
            updatePanelContentKeepingState();

            // 重新聚焦新的输入框
            setTimeout(() => {
                const newInput = document.querySelector(`.todo-list-items[data-list="${listName}"] .add-item-form input`);
                if (newInput) newInput.focus();
            }, 10);
        }

        // 点击添加按钮
        addItemButton.addEventListener('click', e => handleAddFormSubmit(addItemInput, submitNewItem, e));

        // 按下回车键
        addItemInput.addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                handleAddFormSubmit(addItemInput, submitNewItem, e);
                e.preventDefault();
            }
        });

        // 添加删除清单按钮
        const deleteListButton = document.createElement('button');
        deleteListButton.className = 'delete-list-button';
        deleteListButton.textContent = '删除此清单';

        deleteListButton.addEventListener('click', function(e) {
            stopPropagation(e);

            delete todoData[listName];
            GM_setValue('todo-lists', todoData);

            if (currentOpenedListName === listName) {
                currentOpenedListName = null;
            }

            updatePanelContentKeepingState();
        });

        container.appendChild(deleteListButton);

        // 阻止容器事件冒泡
        container.addEventListener('click', stopPropagation);

        // 恢复滚动位置到 itemsContainer
        newItemsContainer.scrollTop = scrollTop;
    }

    // 显示清单的右键菜单
    function showListContextMenu(event, listName, elements) {
        const contextMenu = elements.contextMenu;

        // 计算菜单位置
        const x = event.clientX;
        const y = event.clientY;

        // 清空菜单内容
        contextMenu.innerHTML = '';

        // 添加菜单标题
        const menuTitle = document.createElement('div');
        menuTitle.className = 'context-menu-title';
        menuTitle.innerHTML = '清单操作';
        contextMenu.appendChild(menuTitle);

        // 添加重命名选项
        const renameButton = document.createElement('button');

        // 添加图标和文本
        const iconSpan = document.createElement('span');
        iconSpan.className = 'menu-icon';
        iconSpan.innerHTML = '✏️';
        renameButton.appendChild(iconSpan);

        const textSpan = document.createElement('span');
        textSpan.className = 'title-text';
        textSpan.textContent = '重命名清单';
        renameButton.appendChild(textSpan);

        renameButton.addEventListener('click', function(e) {
            e.stopPropagation();

            // 隐藏菜单
            contextMenu.style.display = 'none';
            contextMenu.classList.remove('visible');

            // 显示重命名对话框
            renameList(listName, elements);
        });

        contextMenu.appendChild(renameButton);

        // 添加删除选项
        const deleteButton = document.createElement('button');

        // 添加图标和文本
        const deleteIconSpan = document.createElement('span');
        deleteIconSpan.className = 'menu-icon';
        deleteIconSpan.innerHTML = '🗑️';
        deleteButton.appendChild(deleteIconSpan);

        const deleteTextSpan = document.createElement('span');
        deleteTextSpan.className = 'title-text';
        deleteTextSpan.textContent = '删除清单';
        deleteButton.appendChild(deleteTextSpan);

        deleteButton.addEventListener('click', function(e) {
            e.stopPropagation();

            // 隐藏菜单
            contextMenu.style.display = 'none';
            contextMenu.classList.remove('visible');

            // 删除清单
            if (confirm(`确定要删除清单"${listName}"吗?`)) {
                delete todoData[listName];
                GM_setValue('todo-lists', todoData);

                if (currentOpenedListName === listName) {
                    currentOpenedListName = null;
                }

                updatePanelContentKeepingState();
            }
        });

        contextMenu.appendChild(deleteButton);

        // 显示菜单
        contextMenu.style.display = 'block';
        contextMenu.style.left = x + 'px';
        contextMenu.style.top = y + 'px';

        // 调整位置以确保在可视区域内
        const menuRect = contextMenu.getBoundingClientRect();
        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;

        if (menuRect.right > viewportWidth) {
            contextMenu.style.left = (viewportWidth - menuRect.width - 10) + 'px';
        }

        if (menuRect.bottom > viewportHeight) {
            contextMenu.style.top = (viewportHeight - menuRect.height - 10) + 'px';
        }

        // 添加动画效果
        setTimeout(() => {
            contextMenu.classList.add('visible');
        }, 10);
    }

    // 重命名清单
    function renameList(oldName, elements) {
        const panel = elements.panel;

        // 创建重命名输入框
        const container = document.createElement('div');
        container.style.position = 'absolute';
        container.style.top = '50%';
        container.style.left = '50%';
        container.style.transform = 'translate(-50%, -50%)';
        container.style.backgroundColor = colors.panelBg;
        container.style.padding = '15px';
        container.style.borderRadius = '8px';
        container.style.boxShadow = '0 2px 10px rgba(0,0,0,0.3)';
        container.style.zIndex = '10001';
        container.style.width = '200px';

        // 添加标题
        const title = document.createElement('div');
        title.textContent = '重命名清单';
        title.style.marginBottom = '10px';
        title.style.fontWeight = 'bold';
        title.style.color = colors.textPrimary;
        container.appendChild(title);

        // 添加输入框
        const input = document.createElement('input');
        input.type = 'text';
        input.className = 'list-edit-input';
        input.value = oldName;
        container.appendChild(input);

        // 添加按钮容器
        const buttonContainer = document.createElement('div');
        buttonContainer.style.display = 'flex';
        buttonContainer.style.justifyContent = 'space-between';
        buttonContainer.style.gap = '8px';
        container.appendChild(buttonContainer);

        // 取消按钮
        const cancelButton = document.createElement('button');
        cancelButton.textContent = '取消';
        cancelButton.className = 'action-button';
        cancelButton.style.backgroundColor = '#999';
        cancelButton.style.flex = '1';
        buttonContainer.appendChild(cancelButton);

        // 确认按钮
        const confirmButton = document.createElement('button');
        confirmButton.textContent = '确定';
        confirmButton.className = 'action-button';
        confirmButton.style.flex = '1';
        buttonContainer.appendChild(confirmButton);

        // 添加到面板
        panel.appendChild(container);

        // 自动聚焦输入框
        setTimeout(() => input.focus(), 10);

        // 取消重命名
        function cancelRename() {
            panel.removeChild(container);
        }

        // 确认重命名
        function confirmRename() {
            const newName = input.value.trim();

            if (newName && newName !== oldName) {
                // 检查是否已存在同名清单
                if (todoData[newName]) {
                    alert('已存在同名清单!');
                    input.focus();
                    return;
                }

                // 重命名清单
                todoData[newName] = todoData[oldName];
                delete todoData[oldName];
                GM_setValue('todo-lists', todoData);

                // 更新当前打开的清单名称
                if (currentOpenedListName === oldName) {
                    currentOpenedListName = newName;
                }

                // 更新面板
                updatePanelContentKeepingState();
            }

            // 移除输入框
            panel.removeChild(container);
        }

        // 事件监听
        cancelButton.addEventListener('click', cancelRename);
        confirmButton.addEventListener('click', confirmRename);

        // 按下回车键确认
        input.addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                confirmRename();
                e.preventDefault();
            }
        });

        // 按下ESC键取消
        input.addEventListener('keydown', function(e) {
            if (e.key === 'Escape') {
                cancelRename();
                e.preventDefault();
            }
        });

        // 阻止事件冒泡
        container.addEventListener('click', e => e.stopPropagation());
    }

    // 更新面板内容的同时保持当前打开的清单状态
    function updatePanelContentKeepingState() {
        // 保存当前打开的清单的滚动位置
        let currentScrollTop = 0;
        if (currentOpenedListName) {
            const currentList = document.querySelector(`.todo-list-items[data-list="${currentOpenedListName}"]`);
            if (currentList) {
                const itemsContainer = currentList.querySelector('.todo-items-container');
                if (itemsContainer) {
                    currentScrollTop = itemsContainer.scrollTop;
                }
            }
        }

        // 确保面板保持打开状态
        globalElements.panel.style.display = 'flex';

        // 更新面板内容
        updatePanelContent(globalElements);

        // 如果有当前打开的清单,则重新打开它并恢复滚动位置
        if (currentOpenedListName) {
            const allListItems = document.querySelectorAll('.todo-list-items');
            allListItems.forEach(item => {
                if (item.getAttribute('data-list') === currentOpenedListName) {
                    item.style.display = 'block';
                    updateListItems(item, currentOpenedListName);
                    
                    // 恢复滚动位置
                    const itemsContainer = item.querySelector('.todo-items-container');
                    if (itemsContainer) {
                        itemsContainer.scrollTop = currentScrollTop;
                    }
                }
            });
        }
    }

    // 初始化
    globalElements = createElements();
    initEvents(globalElements);
    updatePanelContent(globalElements);
})();