Milky Way Idle Tasklist

This script provides a persistent, draggable task list window for Milky Way Idle to help track your goals.

目前为 2025-03-31 提交的版本。查看 最新版本

// ==UserScript==
// @name         Milky Way Idle Tasklist
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  This script provides a persistent, draggable task list window for Milky Way Idle to help track your goals.
// @author       Kjay
// @license      MIT License
// @match        https://www.milkywayidle.com/*
// @match        https://test.milkywayidle.com/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function() {
    'use strict';

    // --- Configuration Settings ---
    const checklistId = 'mwi-checklist';
    const checklistTitle = 'Task List';
    const minimizedLabelText = 'List:';
    const MAX_ITEM_LENGTH = 40;
    const TOOLTIP_LENGTH_THRESHOLD = 15;
    const MAX_TOTAL_ITEMS = 15;
    const STORAGE_KEY_POS = 'mwi_checklist_pos';
    const STORAGE_KEY_ITEMS = 'mwi_checklist_items_v4';
    const STORAGE_KEY_CONFIG = 'mwi_checklist_config_v5';
    const STORAGE_KEY_LAST_SECTION = 'mwi_checklist_last_section';
    const DEFAULT_POS = { top: '10px', left: null, right: '10px' };
    const GLOBAL_SECTION_ID = "__global__";
    const DEFAULT_CONFIG = { sections: [] };

    // --- Styling ---
    // Defines the CSS styles for the checklist UI elements and states.
    const checklistStyle = `
        #${checklistId} { position: fixed; background-color: #333; color: #eee; border: 1px solid #555; padding: 8px; width: 280px; z-index: 2000; display: flex; flex-direction: column; border-radius: 5px; font-family: sans-serif; overflow: hidden; cursor: default; max-height: 90vh; box-sizing: border-box; }
        #${checklistId}.minimized { width: auto; height: auto; padding: 4px 8px; cursor: move; background-color: #222; border: 1px solid #444; border-radius: 5px; display: inline-flex; align-items: center; overflow: visible; max-height: none; }
        #${checklistId}.minimized > *:not(.minimized-content-container) { display: none; }
        #${checklistId} .minimized-content-container { display: none; align-items: center; }
        #${checklistId}.minimized .minimized-content-container { display: inline-flex; }
        #${checklistId} .minimized-label { color: #eee; margin-right: 5px; cursor: move; user-select: none; }
        #${checklistId} .toggle-button { background-color: #4CAF50; color: white; padding: 2px 5px; border-radius: 3px; text-decoration: none; font-size: 0.9em; cursor: pointer; border: none; line-height: normal; vertical-align: middle; }
        #${checklistId} .show-button { display: none; margin-left: 5px; }
        #${checklistId}.minimized .show-button { display: inline-block; }
        #${checklistId} .header-buttons-container { position: absolute; top: 6px; right: 6px; display: flex; gap: 4px; align-items: center; z-index: 1; }
        #${checklistId} .hide-button { order: 1; }
        #${checklistId} h3 { margin: -8px -8px 5px -8px; padding: 5px 35px 5px 8px; text-align: center; cursor: move; background-color: #444; color: #fff; font-size: 1.2em; flex: 0 0 auto; position: relative; border-bottom: 1px solid #555; user-select: none; }
        #${checklistId} #settingsToggleLabel { font-size: 0.9em; color: #ccc; cursor: pointer; margin: 0 0 5px 0; display: block; text-align: center; flex-shrink: 0; border-top: 1px solid #555; padding-top: 5px; }
        #${checklistId}.minimized #settingsToggleLabel { display: none; }
        #${checklistId} #settingsArea { display: none; flex-direction: column; gap: 8px; background-color: #3a3a3a; padding: 8px; margin-bottom: 5px; border-radius: 3px; border: 1px solid #555; font-size: 0.9em; flex-shrink: 0; }
        #${checklistId}.minimized #settingsArea { display: none !important; }
        #${checklistId} #settingsArea > div:not(.settings-section-name) { display: flex; align-items: center; margin-bottom: 5px; }
        #${checklistId} #settingsArea label { margin-right: 5px; display: inline-block; width: 60px; text-align: right; flex-shrink: 0; }
        #${checklistId} #settingsArea input[type=text] { background-color: #444; color: #eee; border: 1px solid #555; padding: 2px 4px; border-radius: 3px; margin-right: 5px; flex-grow: 1; }
        #${checklistId} #settingsArea select { background-color: #444; color: #eee; border: 1px solid #555; padding: 2px; border-radius: 3px; }
        #${checklistId} #settingsArea button { font-size: 0.9em; padding: 2px 5px; background-color: #4CAF50; border: none; color: white; cursor: pointer; }
        #${checklistId} .settings-section-name { display: none; flex-direction: column; margin-bottom: 8px; padding-left: 5px; border-left: 2px solid transparent; }
        #${checklistId} .settings-section-name.visible { display: flex; }
        #${checklistId} .settings-input-row { display: flex; align-items: center; width: 100%; }
        #${checklistId} .remove-indicator { font-size: 0.85em; color: #ffc107; margin-left: 68px; margin-top: 2px; font-style: italic; display: none; line-height: 1.2; }
        #${checklistId} .settings-section-name.marked-for-removal { border-left-color: #ffc107; padding-left: 3px; }
        #${checklistId} .settings-section-name.marked-for-removal .remove-indicator { display: block; }
        #${checklistId} .list-controls { display: flex; justify-content: center; align-items: center; padding: 0 5px 5px 5px; font-size: 0.85em; color: #bbb; flex-shrink: 0; position: relative; height: auto; margin-bottom: 5px; }
        #${checklistId}.minimized .list-controls { display: none; }
        #${checklistId} #taskCounter { flex-grow: 1; text-align: center; line-height: 18px; }
        #${checklistId} #taskCounter.full { color: #ffc107; font-weight: bold; }
        #${checklistId} #addButton { background-color: #4CAF50; border: none; color: white; padding: 3px 6px; text-align: center; text-decoration: none; display: inline-block; font-size: 0.9em; cursor: pointer; border-radius: 3px; flex-shrink: 0; }
        #${checklistId} .clear-list-button { background-color: #fd7e14 !important; color: white; border: none; padding: 1px 4px; font-size: 0.8em; border-radius: 3px; cursor: pointer; }
        #${checklistId} #clearAllButton { position: absolute; right: 5px; top: 0px; }
        #${checklistId} .delete-button { background-color: #f44336; padding: 3px 4px; flex-shrink: 0; border: none; color: white; font-size: 0.9em; cursor: pointer; border-radius: 3px; }
        #${checklistId} #sectionContainer { flex-grow: 1; overflow-y: auto; min-height: 50px; border-top: 1px solid #555; padding-top: 5px; margin-top: 0; padding-right: 4px; }
        #${checklistId} .task-section { margin-bottom: 10px; }
        #${checklistId} .task-section h4 { margin: 0 0 0 3px; font-size: 0.95em; color: #ddd; border-bottom: none; padding-bottom: 0; flex-grow: 1; }
        #${checklistId} .section-header { display: flex; justify-content: space-between; align-items: center; margin: 0 0 3px 0; border-bottom: 1px dotted #666; padding-bottom: 2px; padding-right: 4px; cursor: default; }
        #${checklistId} .clear-section-button { background-color: #fd7e14; color: white; border: none; padding: 0px 3px; font-size: 0.75em; border-radius: 3px; cursor: pointer; line-height: 1.4; flex-shrink: 0; }
        #${checklistId} .task-section ul, #${checklistId} .completed-section ul { list-style: none; padding: 5px 0; margin: 0; min-height: 15px; position: relative; box-sizing: border-box; }
        #${checklistId} ul { list-style: none; padding: 0; margin: 0; }
        #${checklistId} li { margin-bottom: 3px; display: flex; align-items: center; padding: 2px 0; border: 1px solid transparent; transition: background-color 0.1s ease; position: relative; }
        #${checklistId} li.dragging { outline: 2px dashed #aaa; background: #444; opacity: 0.7; }
        #${checklistId} li.drag-over-before { border-top: 2px solid #4CAF50; }
        #${checklistId} li.drag-over-after { border-bottom: 2px solid #4CAF50; }
        #${checklistId} ul.drag-over-empty { border-top: 2px solid #4CAF50; margin-top: -2px; }
        #${checklistId} .drag-handle { cursor: grab; margin-right: 8px; margin-left: 3px; opacity: 0.7; user-select: none; line-height: 1; padding: 0 3px; }
        #${checklistId} .drag-handle:hover { opacity: 1; }
        #${checklistId} input[type="checkbox"] { margin-right: 5px; cursor: pointer; flex-shrink: 0; }
        #${checklistId} .item-text { flex-grow: 1; margin-right: 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: text; }
        #${checklistId} .edit-input { flex-grow: 1; margin-right: 5px; background-color: #555; color: #eee; border: 1px solid #777; padding: 1px 3px; border-radius: 2px; font-size: inherit; font-family: inherit; }
        #${checklistId} #addItemDiv { display: flex; flex-direction: column; flex-shrink: 0; margin-top: 8px; border-top: 1px solid #555; padding-top: 8px; }
        #${checklistId}.minimized #addItemDiv { display: none; }
        #${checklistId} .add-item-row1 { display: flex; align-items: center; margin-bottom: 4px; }
        #${checklistId} #addSectionLabel { margin-right: 5px; font-size: 0.9em; color: #ccc; flex-shrink: 0; }
        #${checklistId} #sectionSelect { background-color: #444; color: #eee; border: 1px solid #555; padding: 3px; border-radius: 3px; font-size: 0.9em; flex-grow: 1; max-width: none; }
        #${checklistId} .add-item-row2 { display: flex; align-items: center; }
        #${checklistId} #addItemInput { flex-grow: 1; margin-right: 5px; background-color: #444; color: #eee; border: 1px solid #555; padding: 3px 5px; border-radius: 3px; min-width: 50px; }
        #${checklistId} #addItemInput:disabled, #${checklistId} #addButton:disabled, #${checklistId} #sectionSelect:disabled { opacity: 0.5; cursor: not-allowed; }
        #${checklistId} .completed-section { margin-top: 8px; border-top: 1px solid #555; padding-top: 5px; flex-shrink: 0; }
        #${checklistId}.minimized .completed-section { display: none; }
        #${checklistId} .completed-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 3px; cursor: default; /* Add default cursor */ }
        #${checklistId} .completed-section ul { opacity: 0.7; max-height: 150px; overflow-y: auto; }
        #${checklistId} .completed-section h4 { margin: 0; font-size: 0.9em; color: #bbb; }
        #${checklistId} [title] { cursor: help; }
        #${checklistId} .task-section.drag-over-section, #${checklistId} .completed-section.drag-over-section { background-color: #404040 !important; outline: 1px dashed #888; outline-offset: -1px; }
    `;
    GM_addStyle(checklistStyle);

    // --- Helper: Generate Unique ID ---
    function generateUniqueId() {
        return Date.now().toString(36) + Math.random().toString(36).substring(2, 7);
    }

    // --- Storage & Config Functions ---
    function getSavedConfig() {
        let configJson = GM_getValue(STORAGE_KEY_CONFIG, JSON.stringify(DEFAULT_CONFIG));
        let config;
        try {
            config = JSON.parse(configJson);
        } catch (e) {
            console.error("MWI Tasklist: Error parsing config JSON. Resetting.", e, configJson);
            config = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
        }
        let needsSave = false;
        if (config && config.hasOwnProperty('count') && config.hasOwnProperty('names') && !config.hasOwnProperty('sections')) {
            console.log("MWI Tasklist: Migrating config from old format.");
            const newConfig = { sections: [] };
            for (let i = 0; i < config.count; i++) {
                const name = config.names[i] || `Character ${i + 1}`;
                newConfig.sections.push({ id: generateUniqueId(), name: name });
            }
            config = newConfig;
            needsSave = true;
        }
        if (!config || typeof config !== 'object' || !Array.isArray(config.sections)) {
            console.warn("MWI Tasklist: Invalid config structure found. Resetting to default.");
            config = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
            needsSave = true;
        }
        config.sections = config.sections.map(s => {
            if (!s || typeof s !== 'object') return null;
            if (!s.id) {
                s.id = generateUniqueId();
                needsSave = true;
            }
            s.name = String(s.name || '').trim().substring(0, MAX_ITEM_LENGTH);
            if (!s.name) {
                 s.name = "Unnamed Section";
                 needsSave = true;
            }
            return s;
        }).filter(s => s !== null);
        if (needsSave) {
            console.log("MWI Tasklist: Saving updated/migrated config.");
            saveConfig(config);
        }
        return config;
    }

    function saveConfig(config) {
        if (!config || !Array.isArray(config.sections)) {
            console.error("MWI Tasklist: Attempted to save invalid config structure.", config);
            return;
        }
        GM_setValue(STORAGE_KEY_CONFIG, JSON.stringify(config));
    }

    function getChecklistItems() {
        let itemsJson = GM_getValue(STORAGE_KEY_ITEMS, '[]');
        let items;
        try {
            items = JSON.parse(itemsJson);
        } catch (e) {
            console.error("MWI Tasklist: Error parsing items JSON. Resetting.", e, itemsJson);
            items = [];
        }
        if (!Array.isArray(items)) {
             console.warn("MWI Tasklist: Invalid items structure found. Resetting to empty array.");
             items = [];
        }
        let needsSave = false;
        items = items.map(item => {
            if (!item || typeof item !== 'object') return null;
            if (!item.id) {
                item.id = generateUniqueId();
                needsSave = true;
            }
            if (item.sectionId === undefined || item.sectionId === null) {
                item.sectionId = GLOBAL_SECTION_ID;
                needsSave = true;
            }
            item.text = String(item.text || '').trim().substring(0, MAX_ITEM_LENGTH);
            item.checked = Boolean(item.checked);
            return item;
        }).filter(item => item !== null);
        if (items.length > MAX_TOTAL_ITEMS) {
            console.warn(`MWI Tasklist: Exceeded MAX_TOTAL_ITEMS (${MAX_TOTAL_ITEMS}). Truncating list.`);
            items = items.slice(0, MAX_TOTAL_ITEMS);
            needsSave = true;
        }
        if (needsSave) {
            console.log("MWI Tasklist: Saving updated/validated items.");
            GM_setValue(STORAGE_KEY_ITEMS, JSON.stringify(items));
        }
        return items;
    }

    function setChecklistItems(items) {
        if (!Array.isArray(items)) {
             console.error("MWI Tasklist: Attempted to save invalid items array.", items);
             return;
        }
        if (items.length > MAX_TOTAL_ITEMS) {
            items = items.slice(0, MAX_TOTAL_ITEMS);
        }
        GM_setValue(STORAGE_KEY_ITEMS, JSON.stringify(items));
    }

    function findActualItemIndexById(itemId, currentItems) {
        if (!itemId || !Array.isArray(currentItems)) return -1;
        return currentItems.findIndex(i => i && i.id === itemId);
    }

    // --- Position Handling ---
    function savePosition(element) {
        if (!element) return;
        if (element.style.left) {
             const pos = {
                top: element.style.top,
                left: element.style.left,
            };
            GM_setValue(STORAGE_KEY_POS, JSON.stringify(pos));
        } else {
             const pos = {
                top: element.style.top,
                right: element.style.right || DEFAULT_POS.right,
             };
             GM_setValue(STORAGE_KEY_POS, JSON.stringify(pos));
        }
    }

    function loadPosition() {
        const savedPos = GM_getValue(STORAGE_KEY_POS, null);
        if (savedPos) {
            try {
                const pos = JSON.parse(savedPos);
                if (pos && typeof pos.top === 'string') {
                    if (typeof pos.left === 'string') {
                        return { top: pos.top, left: pos.left, right: null };
                    } else if (typeof pos.right === 'string') {
                         return { top: pos.top, left: null, right: pos.right };
                    }
                }
            } catch (e) {
                console.error("MWI Tasklist: Error parsing saved position:", e);
                GM_setValue(STORAGE_KEY_POS, null);
            }
        }
        return { ...DEFAULT_POS };
    }


    function applyPosition(element, pos) {
        if (!element || !pos) return;
        element.style.top = pos.top || '';
        element.style.left = pos.left || '';
        element.style.right = pos.right || '';
        if (pos.left) element.style.right = '';
        if (pos.right) element.style.left = '';
    }

    // --- UI Elements Creation Functions ---
    function createChecklistItemElement(item) {
       const listItem = document.createElement('li');
       listItem.dataset.itemId = item.id;
       listItem.dataset.itemSection = item.sectionId;
       const dragHandle = document.createElement('span');
       dragHandle.innerHTML = '☰';
       dragHandle.className = 'drag-handle';
       dragHandle.title = 'Drag to reorder';
       dragHandle.draggable = !item.checked;
       listItem.appendChild(dragHandle);
       const checkbox = document.createElement('input');
       checkbox.type = 'checkbox';
       checkbox.checked = item.checked;
       checkbox.title = item.checked ? 'Mark as incomplete' : 'Mark as complete';
       checkbox.addEventListener('change', () => {
           const items = getChecklistItems();
           const actualIndex = findActualItemIndexById(item.id, items);
           if (actualIndex !== -1) {
               items[actualIndex].checked = checkbox.checked;
               setChecklistItems(items);
               renderChecklist();
           } else {
               console.warn("MWI Tasklist: Could not find item by ID to update checkbox state:", item.id);
           }
       });
       const itemTextSpan = document.createElement('span');
       itemTextSpan.className = 'item-text';
       itemTextSpan.textContent = item.text || '';
       if (item.text && item.text.length > TOOLTIP_LENGTH_THRESHOLD) {
           itemTextSpan.title = item.text;
       }
       itemTextSpan.addEventListener('dblclick', () => {
            if (item.checked) return;
            startEditing(listItem, itemTextSpan, item.id);
        });
       const deleteButton = document.createElement('button');
       deleteButton.textContent = 'X';
       deleteButton.className = 'delete-button';
       deleteButton.title = 'Delete task';
       deleteButton.addEventListener('click', () => {
           const items = getChecklistItems();
           const actualIndex = findActualItemIndexById(item.id, items);
           if(actualIndex !== -1) {
               items.splice(actualIndex, 1);
               setChecklistItems(items);
               renderChecklist();
           } else {
               console.warn("MWI Tasklist: Could not find item by ID to delete:", item.id);
           }
       });
       listItem.appendChild(checkbox);
       listItem.appendChild(itemTextSpan);
       listItem.appendChild(deleteButton);
       if (item.checked) {
           listItem.style.opacity = '0.6';
           itemTextSpan.style.textDecoration = 'line-through';
           dragHandle.style.cursor = 'default';
           dragHandle.style.opacity = '0.2';
           itemTextSpan.style.cursor = 'default';
       }
       return listItem;
    }

    // --- Edit Functionality ---
    function startEditing(listItem, textSpan, itemId) {
       if (listItem.querySelector('.edit-input')) return;
       const currentText = textSpan.textContent;
       const editInput = document.createElement('input');
       editInput.type = 'text';
       editInput.className = 'edit-input';
       editInput.value = currentText;
       editInput.maxLength = MAX_ITEM_LENGTH;
       listItem.replaceChild(editInput, textSpan);
       editInput.focus();
       editInput.select();
       const cleanup = () => {
           editInput.removeEventListener('blur', saveEdit);
           editInput.removeEventListener('keydown', handleKeydown);
           if (listItem.contains(editInput)) {
                listItem.replaceChild(textSpan, editInput);
           }
       };
       const saveEdit = () => {
           let newText = editInput.value.trim();
           listItem.replaceChild(textSpan, editInput);
           if (newText && newText !== currentText) {
               const items = getChecklistItems();
               const actualIndex = findActualItemIndexById(itemId, items);
               if (actualIndex !== -1) {
                   items[actualIndex].text = newText;
                   setChecklistItems(items);
                   textSpan.textContent = newText;
                   if (newText.length > TOOLTIP_LENGTH_THRESHOLD) {
                        textSpan.title = newText;
                    } else {
                        textSpan.removeAttribute('title');
                    }
               } else {
                   console.warn("MWI Tasklist: Could not find item by ID to save edit:", itemId);
                   textSpan.textContent = currentText;
               }
           } else if (!newText) {
                textSpan.textContent = currentText;
                console.log("MWI Tasklist: Edit cancelled, new text is empty.");
           } else {
               textSpan.textContent = currentText;
           }
           cleanup();
       };
       const cancelEdit = () => {
           listItem.replaceChild(textSpan, editInput);
           textSpan.textContent = currentText;
           cleanup();
       };
       const handleKeydown = (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                saveEdit();
            } else if (e.key === 'Escape') {
                cancelEdit();
            }
        };
       editInput.addEventListener('blur', saveEdit);
       editInput.addEventListener('keydown', handleKeydown);
    }

    // --- Render Checklist ---
    function renderChecklist() {
        const checklistDiv = document.getElementById(checklistId);
        if (!checklistDiv || checklistDiv.classList.contains('minimized')) {
            return;
        }
        const elements = {
            sectionContainer: checklistDiv.querySelector('#sectionContainer'),
            completedUl: checklistDiv.querySelector('.completed-section ul'),
            taskCounter: checklistDiv.querySelector('#taskCounter'),
            addItemInput: checklistDiv.querySelector('#addItemInput'),
            addButton: checklistDiv.querySelector('#addButton'),
            sectionSelect: checklistDiv.querySelector('#sectionSelect')
        };
        if (!elements.sectionContainer || !elements.completedUl || !elements.taskCounter || !elements.addItemInput || !elements.addButton || !elements.sectionSelect) {
            console.error("MWI Tasklist: Checklist UI elements missing during render!");
            return;
        }
        const config = getSavedConfig();
        const items = getChecklistItems();
        const totalItemCount = items.length;
        let activeItemCount = 0;
        const lastSectionId = GM_getValue(STORAGE_KEY_LAST_SECTION, GLOBAL_SECTION_ID);
        const scrollPositions = new Map();
        elements.sectionContainer.querySelectorAll('ul[data-section-id]').forEach(ul => {
            scrollPositions.set(ul.dataset.sectionId, ul.scrollTop);
        });
         if (elements.completedUl) {
            scrollPositions.set('__completed__', elements.completedUl.scrollTop);
        }
        elements.sectionContainer.innerHTML = '';
        elements.completedUl.innerHTML = '';
        elements.sectionSelect.innerHTML = '';
        const sectionMap = new Map();
        const createOption = (value, text, isSelected) => {
            const option = document.createElement('option');
            option.value = value;
            option.textContent = text;
            if (isSelected) option.selected = true;
            elements.sectionSelect.appendChild(option);
        };
        createOption(GLOBAL_SECTION_ID, 'Global', lastSectionId === GLOBAL_SECTION_ID);
        const createSectionDOM = (titleText, sectionId) => {
            const sectionDiv = document.createElement('div');
            sectionDiv.className = 'task-section';
            const headerDiv = document.createElement('div');
            headerDiv.className = 'section-header';
            const title = document.createElement('h4');
            title.textContent = titleText;
            headerDiv.appendChild(title);
            const clearButton = document.createElement('button');
            clearButton.textContent = 'Clear';
            clearButton.className = 'clear-section-button clear-list-button';
            clearButton.title = `Clear active tasks in '${titleText}'`;
            clearButton.dataset.sectionId = sectionId;
            clearButton.addEventListener('click', handleClearSection);
            headerDiv.appendChild(clearButton);
            sectionDiv.appendChild(headerDiv);
            const ul = document.createElement('ul');
            ul.dataset.sectionId = sectionId;
            sectionDiv.appendChild(ul);
            elements.sectionContainer.appendChild(sectionDiv);
            sectionMap.set(sectionId, ul);
            // Attach drag listeners to the list (UL) for item handling
            enableDragSort(ul);
            // Attach drag listeners to the header DIV for dropping onto the section header
            enableDragSort(headerDiv);
        };
        createSectionDOM('Global Tasks', GLOBAL_SECTION_ID);
        config.sections.forEach(section => {
            if (!section || !section.id || !section.name) return;
            createOption(section.id, section.name, lastSectionId === section.id);
            createSectionDOM(section.name, section.id);
        });
        items.forEach((item) => {
            if (!item || !item.id) return;
            const listItem = createChecklistItemElement(item);
            if (item.checked) {
                elements.completedUl.appendChild(listItem);
            } else {
                activeItemCount++;
                const currentItemSectionId = item.sectionId || GLOBAL_SECTION_ID;
                const targetUl = sectionMap.get(currentItemSectionId);
                if (targetUl) {
                    targetUl.appendChild(listItem);
                } else {
                    console.warn(`MWI Tasklist: Item "${item.text}" belongs to non-existent section "${currentItemSectionId}". Moving to Global.`);
                    sectionMap.get(GLOBAL_SECTION_ID).appendChild(listItem);
                }
            }
        });
        let counterText = `(${activeItemCount} / ${MAX_TOTAL_ITEMS})`;
        elements.taskCounter.classList.remove('full');
        if (totalItemCount >= MAX_TOTAL_ITEMS) {
            counterText += ' *FULL*';
            elements.taskCounter.classList.add('full');
        }
        elements.taskCounter.textContent = counterText;
        const isListFull = totalItemCount >= MAX_TOTAL_ITEMS;
        elements.addItemInput.disabled = isListFull;
        elements.addButton.disabled = isListFull;
        sectionMap.forEach((ul, sectionId) => {
            if (scrollPositions.has(sectionId)) {
                ul.scrollTop = scrollPositions.get(sectionId);
            }
        });
        if (elements.completedUl && scrollPositions.has('__completed__')) {
             elements.completedUl.scrollTop = scrollPositions.get('__completed__');
        }
         enableDragSort(elements.completedUl);
         const completedHeader = checklistDiv.querySelector('.completed-section .completed-header');
         if(completedHeader) enableDragSort(completedHeader);
    }

    // --- Event Handler for Clearing a Section ---
    function handleClearSection(event) {
        const sectionIdToClear = event.target.dataset.sectionId;
        if (!sectionIdToClear) return;
        const config = getSavedConfig();
        const sectionInfo = config.sections.find(s => s.id === sectionIdToClear);
        const sectionName = sectionIdToClear === GLOBAL_SECTION_ID ? "Global Tasks" : (sectionInfo?.name || `Section ${sectionIdToClear}`);
        if (confirm(`Clear all ACTIVE tasks in the "${sectionName}" section? (Completed tasks will remain)`)) {
            const currentItems = getChecklistItems();
            const itemsToKeep = currentItems.filter(item => {
                return item.checked || (!item.checked && (item.sectionId || GLOBAL_SECTION_ID) !== sectionIdToClear);
            });
            setChecklistItems(itemsToKeep);
            renderChecklist();
        }
    }

     // --- Settings Handlers ---
     function toggleSettingsArea() {
         const settingsArea = document.getElementById('settingsArea');
         const settingsLabel = document.getElementById('settingsToggleLabel');
         if (!settingsArea || !settingsLabel) return;
         const isVisible = settingsArea.style.display === 'flex';
         settingsArea.style.display = isVisible ? 'none' : 'flex';
         settingsLabel.textContent = isVisible ? 'Task Sections Settings ▼' : 'Task Sections Settings ▲';
         if (!isVisible) {
             const currentConfig = getSavedConfig();
             const countSelect = document.getElementById('settingsSectionCount');
             countSelect.value = currentConfig.sections.length;
             for(let i = 0; i < 3; i++) {
                 const nameInput = settingsArea.querySelector(`#settingsSectionName${i+1}`);
                 const inputDiv = settingsArea.querySelector(`#settingsSectionNameDiv${i+1}`);
                 if (nameInput && inputDiv) {
                     const sectionData = currentConfig.sections[i];
                     nameInput.value = sectionData ? sectionData.name : '';
                     inputDiv.classList.toggle('visible', i < currentConfig.sections.length);
                     inputDiv.classList.remove('marked-for-removal');
                 }
             }
             updateSectionNameInputs(currentConfig.sections.length, currentConfig.sections.length);
         }
     }

     function updateSectionNameInputs(selectedCount, savedCount) {
         const settingsArea = document.getElementById('settingsArea');
         if (!settingsArea) return;
         for (let i = 0; i < 3; i++) {
             const inputDiv = settingsArea.querySelector(`#settingsSectionNameDiv${i+1}`);
             const nameInput = inputDiv?.querySelector(`#settingsSectionName${i+1}`);
             if (inputDiv && nameInput) {
                 const shouldBeVisibleForSelection = i < selectedCount;
                 const existsInSavedConfig = i < savedCount;
                 const shouldDisplay = shouldBeVisibleForSelection || (existsInSavedConfig && !shouldBeVisibleForSelection);
                 inputDiv.classList.toggle('visible', shouldDisplay);
                 const markedForRemoval = existsInSavedConfig && !shouldBeVisibleForSelection;
                 inputDiv.classList.toggle('marked-for-removal', markedForRemoval);
             }
         }
     }

     function saveSettingsHandler() {
         const currentConfig = getSavedConfig();
         const countSelect = document.getElementById('settingsSectionCount');
         const newCount = parseInt(countSelect.value, 10);
         const newSections = [];
         const preservedSectionIds = new Set([GLOBAL_SECTION_ID]);
         let itemsModified = false;
         const namesEncountered = new Set();
         for (let i = 0; i < newCount; i++) {
             const nameInput = document.getElementById(`settingsSectionName${i+1}`);
             let baseName = (nameInput.value.trim() || `Character ${i+1}`).substring(0, MAX_ITEM_LENGTH);
             let name = baseName;
             let duplicateCounter = 1;
             while (namesEncountered.has(name) || name === 'Global') {
                 name = `${baseName}_${duplicateCounter++}`.substring(0, MAX_ITEM_LENGTH);
             }
             namesEncountered.add(name);
             const existingSection = (i < currentConfig.sections.length) ? currentConfig.sections[i] : null;
             const id = existingSection ? existingSection.id : generateUniqueId();
             newSections.push({ id: id, name: name });
             preservedSectionIds.add(id);
         }
         const currentItems = getChecklistItems();
         const updatedItems = currentItems.map(item => {
             if (!item.checked && item.sectionId && item.sectionId !== GLOBAL_SECTION_ID && !preservedSectionIds.has(item.sectionId)) {
                 console.log(`MWI Tasklist: Moving item "${item.text}" from removed section ${item.sectionId} to Global.`);
                 item.sectionId = GLOBAL_SECTION_ID;
                 itemsModified = true;
             }
             return item;
         });
         if (itemsModified) {
             setChecklistItems(updatedItems);
         }
         saveConfig({ sections: newSections });
         toggleSettingsArea();
         renderChecklist();
     }

    // --- Create UI ---
    function createChecklistUI() {
        if (document.getElementById(checklistId)) return;
        const checklistDiv = document.createElement('div');
        checklistDiv.id = checklistId;
        let offsetX, offsetY;
        let isWindowDragging = false;
        function startDrag(e) {
            if (e.target.closest('button, input, select, a, .drag-handle')) return;
             if (!checklistDiv.classList.contains('minimized') && !e.target.matches('h3')) return;
             if (checklistDiv.classList.contains('minimized') && !e.target.matches('.minimized-label, #' + checklistId + '.minimized')) return;
            isWindowDragging = true;
            checklistDiv.style.cursor = 'grabbing';
            const rect = checklistDiv.getBoundingClientRect();
            offsetX = e.clientX - rect.left;
            offsetY = e.clientY - rect.top;
            checklistDiv.style.right = '';
            checklistDiv.style.left = rect.left + 'px';
            checklistDiv.style.top = rect.top + 'px';
            document.addEventListener('mousemove', dragWindow);
            document.addEventListener('mouseup', stopWindowDrag, { once: true });
            e.preventDefault();
        }
        function dragWindow(e) {
            if (!isWindowDragging) return;
            let newX = e.clientX - offsetX;
            let newY = e.clientY - offsetY;
            newX = Math.max(0, Math.min(newX, window.innerWidth - checklistDiv.offsetWidth));
            newY = Math.max(0, Math.min(newY, window.innerHeight - checklistDiv.offsetHeight));
            checklistDiv.style.left = newX + 'px';
            checklistDiv.style.top = newY + 'px';
        }
        function stopWindowDrag() {
            if (!isWindowDragging) return;
            isWindowDragging = false;
            checklistDiv.style.cursor = checklistDiv.classList.contains('minimized') ? 'move' : 'default';
            savePosition(checklistDiv);
            document.removeEventListener('mousemove', dragWindow);
        }
        function addItem() {
            const addItemInput = document.getElementById('addItemInput');
            const sectionSelect = document.getElementById('sectionSelect');
            if (!addItemInput || !sectionSelect) return;
            const selectedSectionId = sectionSelect.value;
            let newItemText = addItemInput.value.trim();
            if (newItemText.length > MAX_ITEM_LENGTH) {
                newItemText = newItemText.substring(0, MAX_ITEM_LENGTH);
                addItemInput.value = newItemText;
            }
            if (newItemText) {
                const currentItems = getChecklistItems();
                if (currentItems.length >= MAX_TOTAL_ITEMS) {
                    alert(`Maximum number of tasks (${MAX_TOTAL_ITEMS}) reached.`);
                    return;
                }
                const newItem = {
                    id: generateUniqueId(),
                    text: newItemText,
                    checked: false,
                    sectionId: selectedSectionId
                };
                currentItems.push(newItem);
                setChecklistItems(currentItems);
                GM_setValue(STORAGE_KEY_LAST_SECTION, selectedSectionId);
                renderChecklist();
                addItemInput.value = '';
                addItemInput.focus();
            }
        }
        applyPosition(checklistDiv, loadPosition());
        checklistDiv.classList.add('minimized');
        const minimizedContainer = document.createElement('div');
        minimizedContainer.className = 'minimized-content-container';
        const minimizedLabel = document.createElement('span');
        minimizedLabel.className = 'minimized-label';
        minimizedLabel.textContent = minimizedLabelText;
        minimizedContainer.appendChild(minimizedLabel);
        const showButton = document.createElement('a');
        showButton.href = '#';
        showButton.role = 'button';
        showButton.className = 'show-button toggle-button';
        showButton.textContent = 'Show';
        showButton.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            checklistDiv.classList.remove('minimized');
            applyPosition(checklistDiv, loadPosition());
            renderChecklist();
        });
        minimizedContainer.appendChild(showButton);
        checklistDiv.appendChild(minimizedContainer);
        const title = document.createElement('h3');
        title.textContent = checklistTitle;
        title.addEventListener('mousedown', startDrag);
        checklistDiv.appendChild(title);
        const headerButtonsContainer = document.createElement('div');
        headerButtonsContainer.className = 'header-buttons-container';
        const hideButton = document.createElement('button');
        hideButton.className = 'hide-button toggle-button';
        hideButton.textContent = 'Hide';
        hideButton.title = 'Minimize list';
        hideButton.addEventListener('click', (e) => {
            e.stopPropagation();
            savePosition(checklistDiv);
            checklistDiv.classList.add('minimized');
        });
        headerButtonsContainer.appendChild(hideButton);
        checklistDiv.appendChild(headerButtonsContainer);
        const listControlsDiv = document.createElement('div');
        listControlsDiv.className = 'list-controls';
        const taskCounterDiv = document.createElement('span');
        taskCounterDiv.id = 'taskCounter';
        taskCounterDiv.textContent = `(0 / ${MAX_TOTAL_ITEMS})`;
        listControlsDiv.appendChild(taskCounterDiv);
        const clearAllButton = document.createElement('button');
        clearAllButton.id = 'clearAllButton';
        clearAllButton.textContent = 'Clear All';
        clearAllButton.title = 'Delete ALL tasks (active and completed)';
        clearAllButton.classList.add('clear-list-button');
        clearAllButton.addEventListener('click', () => {
            if (confirm('Are you sure you want to delete ALL tasks? This cannot be undone.')) {
                setChecklistItems([]);
                renderChecklist();
            }
        });
        listControlsDiv.appendChild(clearAllButton);
        checklistDiv.appendChild(listControlsDiv);
        const settingsToggleLabel = document.createElement('div');
        settingsToggleLabel.id = 'settingsToggleLabel';
        settingsToggleLabel.textContent = 'Task Sections Settings ▼';
        settingsToggleLabel.title = 'Show/hide section management';
        settingsToggleLabel.style.cursor = 'pointer';
        settingsToggleLabel.addEventListener('click', toggleSettingsArea);
        checklistDiv.appendChild(settingsToggleLabel);
        const settingsArea = document.createElement('div');
        settingsArea.id = 'settingsArea';
        settingsArea.innerHTML = `
            <div>
                <label for="settingsSectionCount">Sections:</label>
                <select id="settingsSectionCount" title="Number of custom sections (0-3)">
                    <option value="0">0</option>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
            </div>
            <div id="settingsSectionNameDiv1" class="settings-section-name">
                <div class="settings-input-row">
                    <label for="settingsSectionName1">Name 1:</label>
                    <input type="text" id="settingsSectionName1" maxlength="${MAX_ITEM_LENGTH}">
                </div>
                <span class="remove-indicator">(tasks will move to Global)</span>
            </div>
            <div id="settingsSectionNameDiv2" class="settings-section-name">
                 <div class="settings-input-row">
                    <label for="settingsSectionName2">Name 2:</label>
                    <input type="text" id="settingsSectionName2" maxlength="${MAX_ITEM_LENGTH}">
                </div>
                <span class="remove-indicator">(tasks will move to Global)</span>
            </div>
            <div id="settingsSectionNameDiv3" class="settings-section-name">
                 <div class="settings-input-row">
                    <label for="settingsSectionName3">Name 3:</label>
                    <input type="text" id="settingsSectionName3" maxlength="${MAX_ITEM_LENGTH}">
                </div>
                <span class="remove-indicator">(tasks will move to Global)</span>
            </div>
            <button id="saveSettingsButton" title="Save section changes">Save Settings</button>
        `;
        checklistDiv.appendChild(settingsArea);
        const countSelect = settingsArea.querySelector('#settingsSectionCount');
        countSelect.addEventListener('change', () => {
            const currentConfig = getSavedConfig();
            updateSectionNameInputs(parseInt(countSelect.value, 10), currentConfig.sections.length);
        });
        settingsArea.querySelector('#saveSettingsButton').addEventListener('click', saveSettingsHandler);
        const sectionContainer = document.createElement('div');
        sectionContainer.id = 'sectionContainer';
        checklistDiv.appendChild(sectionContainer);
        const completedSection = document.createElement('div');
        completedSection.className = 'completed-section';
        const completedHeaderDiv = document.createElement('div');
        completedHeaderDiv.className = 'completed-header';
        const completedTitle = document.createElement('h4');
        completedTitle.textContent = 'Completed';
        completedHeaderDiv.appendChild(completedTitle);
        const clearCompletedButton = document.createElement('button');
        clearCompletedButton.textContent = 'Clear';
        clearCompletedButton.classList.add('clear-list-button');
        clearCompletedButton.title = 'Delete all completed tasks';
        clearCompletedButton.addEventListener('click', () => {
            if (confirm('Are you sure you want to delete all COMPLETED tasks?')) {
                const items = getChecklistItems();
                const activeItems = items.filter(item => !item.checked);
                setChecklistItems(activeItems);
                renderChecklist();
            }
        });
        completedHeaderDiv.appendChild(clearCompletedButton);
        completedSection.appendChild(completedHeaderDiv);
        const completedUl = document.createElement('ul');
        completedUl.dataset.sectionId = "__completed__";
        completedSection.appendChild(completedUl);
        checklistDiv.appendChild(completedSection);
        const addItemDiv = document.createElement('div');
        addItemDiv.id = "addItemDiv";
        const addItemRow1 = document.createElement('div');
        addItemRow1.className = 'add-item-row1';
        const addSectionLabel = document.createElement('label');
        addSectionLabel.id = 'addSectionLabel';
        addSectionLabel.textContent = 'Add To:';
        addSectionLabel.htmlFor = 'sectionSelect';
        const sectionSelectDropdown = document.createElement('select');
        sectionSelectDropdown.id = 'sectionSelect';
        sectionSelectDropdown.title = 'Choose section for new task';
        addItemRow1.appendChild(addSectionLabel);
        addItemRow1.appendChild(sectionSelectDropdown);
        const addItemRow2 = document.createElement('div');
        addItemRow2.className = 'add-item-row2';
        const addItemInput = document.createElement('input');
        addItemInput.id = 'addItemInput';
        addItemInput.type = 'text';
        addItemInput.placeholder = 'New item text';
        addItemInput.maxLength = MAX_ITEM_LENGTH;
        addItemInput.addEventListener('keydown', (event) => {
            if (event.key === 'Enter' && !addItemInput.disabled) {
                 event.preventDefault();
                 addItem();
            }
        });
        const addButton = document.createElement('button');
        addButton.id = 'addButton';
        addButton.textContent = 'Add';
        addButton.title = 'Add new task to selected section';
        addButton.addEventListener('click', addItem);
        addItemRow2.appendChild(addItemInput);
        addItemRow2.appendChild(addButton);
        addItemDiv.appendChild(addItemRow1);
        addItemDiv.appendChild(addItemRow2);
        checklistDiv.appendChild(addItemDiv);
        checklistDiv.addEventListener('mousedown', startDrag);
        document.body.appendChild(checklistDiv);
    }

    // --- Drag and Drop Sorting for List Items ---
    let draggedItemElement = null;

    // Function to attach drag event listeners to an element (UL or Header)
    function enableDragSort(element) {
        // Use capturing phase for dragstart to ensure it's handled correctly before potential bubbling issues
        element.removeEventListener('dragstart', handleDragStart, true);
        element.addEventListener('dragstart', handleDragStart, true);

        element.removeEventListener('dragend', handleDragEnd);
        element.addEventListener('dragend', handleDragEnd);

        element.removeEventListener('dragover', handleDragOver);
        element.addEventListener('dragover', handleDragOver);

        element.removeEventListener('dragleave', handleDragLeave);
        element.addEventListener('dragleave', handleDragLeave);

        element.removeEventListener('drop', handleDrop);
        element.addEventListener('drop', handleDrop);
    }

     // Called when dragging starts (attached to UL and Header elements in capturing phase)
     function handleDragStart(e) {
        // Check if the direct target of the event is the drag handle
        if (e.target.classList.contains('drag-handle')) {
            // This is the intended drag start, proceed
            draggedItemElement = e.target.closest('li');
            if (!draggedItemElement) return; // Should have a parent li
            setTimeout(() => {
                if (draggedItemElement) draggedItemElement.classList.add('dragging');
            }, 0);

            e.dataTransfer.effectAllowed = 'move';
            try {
                e.dataTransfer.setData('text/plain', draggedItemElement.dataset.itemId);
            } catch (err) {
                 console.warn("MWI Tasklist: Could not set drag data.", err);
            }
        } else {
             if (e.target.closest(`#${checklistId}`)) {
                  e.preventDefault();
             }
        }
    }

    // Called when dragging ends
    function handleDragEnd(e) {
        // Cleanup is done regardless of success/failure of drop
        if (draggedItemElement) {
            draggedItemElement.classList.remove('dragging');
        }
        // Clear all visual drag indicators from all sections/items
        document.querySelectorAll(`#${checklistId} li.drag-over-before, #${checklistId} li.drag-over-after`).forEach(item => {
             item.classList.remove('drag-over-before', 'drag-over-after');
         });
         document.querySelectorAll(`#${checklistId} ul.drag-over-empty`).forEach(ul => {
             ul.classList.remove('drag-over-empty');
         });
         document.querySelectorAll(`#${checklistId} .task-section.drag-over-section, #${checklistId} .completed-section.drag-over-section`).forEach(sec => {
             sec.classList.remove('drag-over-section');
         });
        draggedItemElement = null; // Clear the reference
    }

     // Called frequently when dragging over a potential drop target
     function handleDragOver(e) {
        e.preventDefault(); // Necessary to allow dropping
        e.dataTransfer.dropEffect = 'move';

        if (!draggedItemElement) return;

        const targetSectionDiv = e.target.closest('.task-section, .completed-section');
        if (!targetSectionDiv) return;

        const targetList = targetSectionDiv.querySelector('ul[data-section-id]');
        if (!targetList) return;

        const targetItem = e.target.closest('li');

        document.querySelectorAll(`#${checklistId} li.drag-over-before, #${checklistId} li.drag-over-after`).forEach(item => {
            item.classList.remove('drag-over-before', 'drag-over-after');
        });
        document.querySelectorAll(`#${checklistId} ul.drag-over-empty`).forEach(ul => {
             ul.classList.remove('drag-over-empty');
         });
         document.querySelectorAll(`#${checklistId} .task-section.drag-over-section, #${checklistId} .completed-section.drag-over-section`).forEach(sec => {
             // Only remove if it's NOT the current target section
             if (sec !== targetSectionDiv) {
                sec.classList.remove('drag-over-section');
             }
         });

        targetSectionDiv.classList.add('drag-over-section'); // Highlight the whole section

        const isListEmpty = !targetList.querySelector('li:not(.dragging)');

        if (targetItem && targetItem !== draggedItemElement && targetItem.parentNode === targetList) {
            const targetRect = targetItem.getBoundingClientRect();
            const isAfter = e.clientY > targetRect.top + targetRect.height / 2;
            targetItem.classList.add(isAfter ? 'drag-over-after' : 'drag-over-before');
        } else if (isListEmpty && !targetItem) {
            targetList.classList.add('drag-over-empty');
        }
    }

    // Called when leaving a potential drop target
    function handleDragLeave(e) {
        if (!e.relatedTarget || !e.relatedTarget.closest(`#${checklistId}`)) {
             // Call handleDragEnd to perform a full cleanup if mouse leaves the list area
             handleDragEnd(e);
        } else {
             const targetSectionDiv = e.target.closest('.task-section, .completed-section');
             if (targetSectionDiv) {
                 const list = targetSectionDiv.querySelector('ul');
                  if (list && !list.contains(e.relatedTarget) && !targetSectionDiv.querySelector('.section-header').contains(e.relatedTarget)) {
                       list.classList.remove('drag-over-empty'); // Remove empty indicator if leaving list area but still in section
                  }
             }
        }
    }


    // Called when dropping an item
    function handleDrop(e) {
        e.preventDefault();
        e.stopPropagation(); // Prevent dropping on multiple nested elements if possible

        const currentDraggedItemElement = draggedItemElement;
        draggedItemElement = null;

        if (!currentDraggedItemElement) {
             handleDragEnd(e); // Clean up visuals if drop happens without a valid dragged item
             return;
        }

        const targetSectionDiv = e.target.closest('.task-section, .completed-section');
        if (!targetSectionDiv) {
            console.warn("MWI Tasklist: Drop occurred outside a valid section.");
            handleDragEnd(e);
            return;
        }

        const targetListElement = targetSectionDiv.querySelector('ul[data-section-id]');
        if (!targetListElement) {
            console.error("MWI Tasklist: Could not find target list within section.");
             handleDragEnd(e);
            return;
        }

        const dropTargetElement = e.target.closest('li');

        // --- Update Data ---
        const targetSectionId = targetListElement.dataset.sectionId;
        const draggedItemId = currentDraggedItemElement.dataset.itemId;

        const allItems = getChecklistItems();
        const draggedItemDataIndex = findActualItemIndexById(draggedItemId, allItems);

        if (draggedItemDataIndex === -1) {
            console.error("MWI Tasklist: Could not find dragged item data by ID:", draggedItemId);
            handleDragEnd(e); // Clean up visuals
            renderChecklist(); // Re-render to reset UI state
            return;
        }

        const [movedItemData] = allItems.splice(draggedItemDataIndex, 1);

         const isDroppingOnCompleted = targetSectionId === '__completed__';
         movedItemData.sectionId = isDroppingOnCompleted ? (movedItemData.sectionId || GLOBAL_SECTION_ID) : targetSectionId;
         movedItemData.checked = isDroppingOnCompleted;

         let finalInsertIndex = -1;
         if (dropTargetElement && dropTargetElement !== currentDraggedItemElement && dropTargetElement.parentNode === targetListElement) {
             const dropTargetItemId = dropTargetElement.dataset.itemId;
             const dropTargetDataIndex = findActualItemIndexById(dropTargetItemId, allItems);
             if (dropTargetDataIndex !== -1) {
                 const targetRect = dropTargetElement.getBoundingClientRect();
                 const isAfter = e.clientY > targetRect.top + targetRect.height / 2;
                 finalInsertIndex = isAfter ? dropTargetDataIndex + 1 : dropTargetDataIndex;
             } else {
                  console.warn("MWI Tasklist: Could not find drop target item data:", dropTargetItemId);
             }
         }

         if (finalInsertIndex === -1) {
              if (isDroppingOnCompleted) {
                  let firstCompletedIndex = allItems.findIndex(item => item.checked);
                   finalInsertIndex = (firstCompletedIndex === -1) ? allItems.length : firstCompletedIndex;
              } else {
                   let insertBeforeIndex = allItems.findIndex(item => item.checked || (item.sectionId || GLOBAL_SECTION_ID) !== targetSectionId);
                   finalInsertIndex = (insertBeforeIndex === -1) ? allItems.length : insertBeforeIndex;
              }
          }

        finalInsertIndex = Math.max(0, Math.min(finalInsertIndex, allItems.length));
        allItems.splice(finalInsertIndex, 0, movedItemData);

        // --- Save and Re-render ---
        setChecklistItems(allItems);
        handleDragEnd(e);
        renderChecklist();
    }


    // --- Initialization ---
    function initialize() {
        if (document.getElementById(checklistId)) {
            console.log("MWI Tasklist: Already initialized.");
            return;
        }
        console.log("MWI Tasklist: Initializing...");
        createChecklistUI();
    }

    // --- Wait for Game Load ---
    function waitForGameLoad() {
        if (document.body) {
            initialize();
        } else {
            setTimeout(waitForGameLoad, 300);
        }
    }

    // --- Script Entry Point ---
    waitForGameLoad();

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址