MediaWiki

Card.js:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
无编辑摘要
律Rhyme留言 | 贡献
无编辑摘要
第1行: 第1行:
/**
// MediaWiki:Card.js
* MediaWiki 卡牌管理器
// 卡牌管理系统
* 用于管理模块:卡牌/角色名的数据
*/


(function() {
(function() {
     'use strict';
     'use strict';
 
   
     const CardManager = {
    // 检查是否在正确的页面
    if (mw.config.get('wgPageName') !== 'MediaWiki:Card') {
        return;
    }
   
    // 卡牌数据存储
     var cardData = {
         cards: [],
         cards: [],
         currentCard: null,
         currentCard: null,
         currentVariantIndex: null,
         currentVariantIndex: null
         characterName: '',
    };
   
    // 字段定义
    var fieldDefinitions = {
        cardOrder: ['art', '卡组', '属性', '稀有度', 'AP', '机制', '类型', '描述', '衍生卡牌'],
        deckTypes: ['', '起始卡牌', '独特卡牌', '灵光一闪', '衍生卡牌', '神光一闪'],
        attributes: ['', '热情', '秩序', '正义', '本能', '虚无'],
         rarities: ['', '白', '蓝', '橙', '彩'],
        types: ['', '攻击', '技能', '强化', '状态异常']
    };
   
    // 创建下拉选择框
    function createDropdown(options, value, placeholder) {
        var container = $('<div>').addClass('card-dropdown-container');
        var input = $('<input>')
            .addClass('card-dropdown-input')
            .attr('placeholder', placeholder || '点击选择或输入...')
            .val(value || '');
       
        var dropdown = $('<div>').addClass('card-dropdown-list').hide();
       
        options.forEach(function(opt) {
            $('<div>')
                .addClass('card-dropdown-item')
                .text(opt || '(空)')
                .click(function() {
                    input.val(opt);
                    dropdown.hide();
                })
                .appendTo(dropdown);
        });
       
        input.on('focus click', function(e) {
            e.stopPropagation();
            $('.card-dropdown-list').hide();
            dropdown.show();
        });
       
        $(document).click(function() {
            dropdown.hide();
        });
       
        container.append(input, dropdown);
        return container;
    }
   
    // 创建表单字段
    function createFormField(label, inputElement) {
        return $('<div>').addClass('card-form-field')
            .append($('<div>').addClass('card-form-label').text(label))
            .append($('<div>').addClass('card-form-input').append(inputElement));
    }
   
    // 初始化界面
    function initUI() {
        var container = $('<div>').attr('id', 'card-editor-container');
       
        // 左侧:输入区
        var leftPanel = $('<div>').addClass('card-panel card-input-panel');
        var formGroup = $('<div>').addClass('card-group').append($('<div>').addClass('card-group-title').text('卡牌数据'));
       
        // 创建表单字段
        var nameInput = $('<input>').attr('id', 'card-name').attr('placeholder', '请输入卡牌名称...');
        formGroup.append(createFormField('卡牌名称:', nameInput));
       
        var deckDropdown = createDropdown(fieldDefinitions.deckTypes, '', '点击选择或输入...');
        formGroup.append(createFormField('卡组类型:', deckDropdown));
       
        var artContainer = $('<div>').addClass('card-art-container');
        var artInput = $('<input>').attr('id', 'card-art').attr('placeholder', '输入图片文件名...');
        artContainer.append(artInput);
        formGroup.append(createFormField('图片文件:', artContainer));
       
        var attrDropdown = createDropdown(fieldDefinitions.attributes, '', '点击选择...');
        formGroup.append(createFormField('属性:', attrDropdown));
       
        var rarityDropdown = createDropdown(fieldDefinitions.rarities, '', '点击选择...');
        formGroup.append(createFormField('稀有度:', rarityDropdown));
       
        var apInput = $('<input>').attr('id', 'card-ap').attr('placeholder', '输入AP数值...');
        formGroup.append(createFormField('AP (行动点):', apInput));
       
        var typeDropdown = createDropdown(fieldDefinitions.types, '', '点击选择...');
        formGroup.append(createFormField('卡牌类型:', typeDropdown));
       
        var mechanismInput = $('<input>').attr('id', 'card-mechanism').attr('placeholder', '请输入卡牌机制...');
        formGroup.append(createFormField('卡牌机制:', mechanismInput));
       
        // 描述区域
        var descContainer = $('<div>').addClass('card-desc-container');
        var descHeader = $('<div>').addClass('card-desc-header')
            .append($('<span>').text('卡牌描述:'))
            .append($('<div>').addClass('card-desc-buttons')
                .append($('<div>').addClass('card-button card-button-small card-button-blue').text('蓝色文本').click(function() { insertTextFormat('蓝'); }))
                .append($('<div>').addClass('card-button card-button-small card-button-green').text('绿色文本').click(function() { insertTextFormat('绿'); }))
                .append($('<div>').addClass('card-button card-button-small card-button-stroke').text('绿色描边').click(insertStrokeFormat))
                .append($('<div>').addClass('card-button card-button-small card-button-br').text('插入换行').click(insertBr))
            );
       
        var descTextarea = $('<textarea>').attr('id', 'card-desc').attr('placeholder', '请输入卡牌描述...');
        descContainer.append(descHeader, descTextarea);
        formGroup.append(descContainer);
          
          
         // 初始化
         var derivedInput = $('<input>').attr('id', 'card-derived').attr('placeholder', '请输入衍生卡牌...');
        init: function() {
        formGroup.append(createFormField('衍生卡牌:', derivedInput));
            this.characterName = this.getCharacterName();
            this.createUI();
            this.bindEvents();
            this.loadCardModule();
        },
          
          
         // 创建UI
        leftPanel.append(formGroup);
         createUI: function() {
       
            const container = document.getElementById('card-manager-root');
         // 按钮区
            if (!container) return;
         var buttonContainer = $('<div>').addClass('card-button-container');
              
        buttonContainer.append(
            container.innerHTML = `
             $('<div>').addClass('card-button card-button-add').text('添加卡牌').click(addCard),
                <h2>卡牌数据管理器</h2>
            $('<div>').addClass('card-button card-button-add').text('添加变体').click(addVariant),
                <div class="cm-container">
            $('<div>').addClass('card-button').text('保存数据').click(saveData),
                    <div class="cm-section cm-input-section">
            $('<div>').addClass('card-button').text('清空表单').click(clearForm)
                        <div class="cm-section-title">卡牌数据</div>
        );
                       
        leftPanel.append(buttonContainer);
                        <div class="cm-form-group">
       
                            <div class="cm-label">卡牌名称:</div>
        // 中间:列表区
                            <input type="text" id="card-name" class="cm-input" placeholder="请输入卡牌名称...">
        var middlePanel = $('<div>').addClass('card-panel card-list-panel');
                        </div>
       
                       
        var cardListGroup = $('<div>').addClass('card-group')
                        <div class="cm-form-group">
            .append($('<div>').addClass('card-group-title').text('卡牌列表'))
                            <div class="cm-label">卡组类型:</div>
            .append($('<div>').attr('id', 'card-list').addClass('card-list'));
                            <input type="text" id="deck-type" class="cm-input" list="deck-list" placeholder="请选择或输入...">
        middlePanel.append(cardListGroup);
                            <datalist id="deck-list">
       
                                <option value="起始卡牌">
        var variantListGroup = $('<div>').addClass('card-group')
                                <option value="独特卡牌">
            .append($('<div>').addClass('card-group-title').text('变体列表'))
                                <option value="灵光一闪">
            .append($('<div>').attr('id', 'variant-list').addClass('card-list'));
                                <option value="衍生卡牌">
        middlePanel.append(variantListGroup);
                            </datalist>
       
                        </div>
        var deleteButtons = $('<div>').addClass('card-button-container');
                       
        deleteButtons.append(
                        <div class="cm-form-group">
            $('<div>').addClass('card-button card-button-delete').text('删除卡牌').click(deleteCard),
                            <div class="cm-label">图片文件:</div>
            $('<div>').addClass('card-button card-button-delete').text('删除变体').click(deleteVariant)
                            <input type="text" id="card-art" class="cm-input" placeholder="如: unique_1003_01.png">
        );
                        </div>
        middlePanel.append(deleteButtons);
                       
       
                        <div class="cm-form-group">
        // 右侧:代码显示区
                            <div class="cm-label">属性:</div>
        var rightPanel = $('<div>').addClass('card-panel card-code-panel');
                            <input type="text" id="card-attr" class="cm-input" list="attr-list" placeholder="请选择或输入...">
       
                            <datalist id="attr-list">
        var codeGroup = $('<div>').addClass('card-group')
                                <option value="热情">
            .append($('<div>').addClass('card-group-title').text('Lua代码预览'))
                                <option value="秩序">
            .append($('<textarea>').attr('id', 'code-display').addClass('card-code-display').attr('readonly', true));
                                <option value="正义">
        rightPanel.append(codeGroup);
                                <option value="本能">
       
                                <option value="虚无">
        var codeButtons = $('<div>').addClass('card-button-container');
                            </datalist>
        codeButtons.append(
                        </div>
            $('<div>').addClass('card-button').text('复制代码').click(copyCode),
                       
            $('<div>').addClass('card-button').text('加载数据').click(loadFromWiki),
                        <div class="cm-form-group">
            $('<div>').addClass('card-button').text('保存到Wiki').click(saveToWiki)
                            <div class="cm-label">稀有度:</div>
        );
                            <input type="text" id="card-rarity" class="cm-input" list="rarity-list" placeholder="请选择或输入...">
         rightPanel.append(codeButtons);
                            <datalist id="rarity-list">
                                <option value="白">
                                <option value="蓝">
                                <option value="橙">
                                <option value="彩">
                            </datalist>
                        </div>
                       
                        <div class="cm-form-group">
                            <div class="cm-label">AP (行动点):</div>
                            <input type="text" id="card-ap" class="cm-input" placeholder="输入数字或X">
                        </div>
                       
                        <div class="cm-form-group">
                            <div class="cm-label">卡牌类型:</div>
                            <input type="text" id="card-type" class="cm-input" list="type-list" placeholder="请选择或输入...">
                            <datalist id="type-list">
                                <option value="攻击">
                                <option value="技能">
                                <option value="强化">
                                <option value="状态异常">
                            </datalist>
                        </div>
                       
                        <div class="cm-form-group">
                            <div class="cm-label">卡牌机制:</div>
                            <input type="text" id="card-mechanism" class="cm-input" placeholder="如:消灭">
                        </div>
                       
                        <div class="cm-form-group">
                            <div class="cm-label">卡牌描述:</div>
                            <div class="cm-format-buttons">
                                <span class="cm-btn cm-btn-small cm-btn-blue" data-action="blue-text">蓝色文本</span>
                                <span class="cm-btn cm-btn-small cm-btn-green" data-action="green-text">绿色文本</span>
                                <span class="cm-btn cm-btn-small cm-btn-green" data-action="green-stroke">绿色描边</span>
                                <span class="cm-btn cm-btn-small cm-btn-orange" data-action="insert-br">插入&lt;br&gt;</span>
                            </div>
                            <textarea id="card-desc" class="cm-textarea" placeholder="请输入卡牌描述..."></textarea>
                        </div>
                       
                        <div class="cm-form-group">
                            <div class="cm-label">衍生卡牌:</div>
                            <input type="text" id="card-derived" class="cm-input" placeholder="请输入衍生卡牌名称">
                        </div>
                       
                        <div class="cm-button-group">
                            <span class="cm-btn cm-btn-success" data-action="add-card">添加卡牌</span>
                            <span class="cm-btn cm-btn-success" data-action="add-variant">添加变体</span>
                        </div>
                       
                        <div class="cm-button-group">
                            <span class="cm-btn" data-action="save-card">保存数据</span>
                            <span class="cm-btn" data-action="clear-form">清空表单</span>
                        </div>
                    </div>
                   
                    <div class="cm-section cm-list-section">
                        <div class="cm-section-title">卡牌列表</div>
                        <div id="card-list" class="cm-list"></div>
                       
                        <div class="cm-section-title" style="margin-top: 20px;">变体列表</div>
                        <div id="variant-list" class="cm-list"></div>
                       
                        <div class="cm-button-group">
                            <span class="cm-btn cm-btn-danger" data-action="delete-card">删除卡牌</span>
                            <span class="cm-btn cm-btn-danger" data-action="delete-variant">删除变体</span>
                        </div>
                    </div>
                   
                    <div class="cm-section cm-preview-section">
                        <div class="cm-section-title">Lua代码预览</div>
                        <pre id="code-preview" class="cm-code-preview">-- 暂无数据</pre>
                       
                        <div class="cm-button-group">
                            <span class="cm-btn" data-action="export">导出到模块</span>
                            <span class="cm-btn" data-action="import">从模块导入</span>
                        </div>
                    </div>
                </div>
            `;
         },
          
          
         // 从页面标题获取角色名
         container.append(leftPanel, middlePanel, rightPanel);
        getCharacterName: function() {
        $('#mw-content-text').empty().append(container);
            const match = mw.config.get('wgPageName').match(/模块:卡牌\/(.+)/);
            return match ? match[1] : '';
        },
          
          
         // 绑定事件
         // 初始化拖拽排序
         bindEvents: function() {
         initSortable();
            const container = document.getElementById('card-manager-root');
    }
            if (!container) return;
   
           
    // 初始化拖拽排序
            // 按钮点击事件
    function initSortable() {
            container.addEventListener('click', (e) => {
        mw.loader.using('jquery.ui', function() {
                const target = e.target;
            $('#card-list').sortable({
                const action = target.getAttribute('data-action');
                update: function(event, ui) {
               
                     updateCardOrder();
                if (!action) return;
               
                switch(action) {
                    case 'add-card':
                        this.addCard();
                        break;
                    case 'add-variant':
                        this.addVariant();
                        break;
                    case 'save-card':
                        this.saveCard();
                        break;
                    case 'clear-form':
                        this.clearForm();
                        break;
                    case 'delete-card':
                        this.deleteCard();
                        break;
                    case 'delete-variant':
                        this.deleteVariant();
                        break;
                    case 'export':
                        this.exportToModule();
                        break;
                    case 'import':
                        this.importFromModule();
                        break;
                    case 'blue-text':
                        this.insertFormat('文本', '蓝');
                        break;
                    case 'green-text':
                        this.insertFormat('文本', '绿');
                        break;
                    case 'green-stroke':
                        this.insertFormat('描边', '绿');
                        break;
                    case 'insert-br':
                        this.insertBr();
                        break;
                }
               
                // 处理卡牌和变体选择
                if (target.classList.contains('cm-card-item')) {
                     const index = parseInt(target.getAttribute('data-index'));
                    this.selectCard(index);
                } else if (target.classList.contains('cm-variant-item')) {
                    const index = parseInt(target.getAttribute('data-index'));
                    this.selectVariant(index);
                 }
                 }
             });
             });
           
        });
            // 卡组类型变化
    }
            const deckType = document.getElementById('deck-type');
   
            if (deckType) {
    // 文本格式化函数
                deckType.addEventListener('change', (e) => {
    function insertTextFormat(color) {
                    const isVariant = e.target.value === '灵光一闪';
        var textarea = $('#card-desc')[0];
                    this.toggleVariantFields(isVariant);
        var start = textarea.selectionStart;
                });
        var end = textarea.selectionEnd;
             }
        var text = textarea.value;
         },
        var selectedText = text.substring(start, end);
       
        var newText = text.substring(0, start) +
                      '{{文本|' + color + '|' + selectedText + '}}' +
                      text.substring(end);
       
        textarea.value = newText;
        textarea.focus();
        textarea.setSelectionRange(start + 6 + color.length, start + 6 + color.length + selectedText.length);
    }
   
    function insertStrokeFormat() {
        var textarea = $('#card-desc')[0];
        var start = textarea.selectionStart;
        var end = textarea.selectionEnd;
        var text = textarea.value;
        var selectedText = text.substring(start, end);
       
        var newText = text.substring(0, start) +
                      '{{描边|绿|' + selectedText + '}}' +
                      text.substring(end);
       
        textarea.value = newText;
        textarea.focus();
        textarea.setSelectionRange(start + 7, start + 7 + selectedText.length);
    }
   
    function insertBr() {
        var textarea = $('#card-desc')[0];
        var pos = textarea.selectionStart;
        var text = textarea.value;
       
        var newText = text.substring(0, pos) + '<br>' + text.substring(pos);
        textarea.value = newText;
        textarea.focus();
        textarea.setSelectionRange(pos + 4, pos + 4);
    }
   
    // 获取表单数据
    function getFormData() {
        var variant = {};
       
        var art = $('#card-art').val().trim();
        if (art) variant.art = art;
       
        var deck = $('.card-dropdown-container').eq(0).find('input').val().trim();
        if (deck) variant['卡组'] = deck;
       
        var attr = $('.card-dropdown-container').eq(1).find('input').val().trim();
        if (attr) variant['属性'] = attr;
       
        var rarity = $('.card-dropdown-container').eq(2).find('input').val().trim();
        if (rarity) variant['稀有度'] = rarity;
       
        var ap = $('#card-ap').val().trim();
        if (ap) {
             variant.AP = isNaN(ap) ? ap : parseInt(ap);
        }
          
        var type = $('.card-dropdown-container').eq(3).find('input').val().trim();
        if (type) variant['类型'] = type;
       
        var mechanism = $('#card-mechanism').val().trim();
        if (mechanism) variant['机制'] = mechanism;
          
          
         // 切换变体字段状态
         var desc = $('#card-desc').val().trim();
        toggleVariantFields: function(isVariant) {
        if (desc) variant['描述'] = desc;
            const fields = ['card-name', 'card-art', 'card-attr', 'card-rarity', 'card-derived'];
            fields.forEach(id => {
                const el = document.getElementById(id);
                if (el) el.disabled = isVariant;
            });
        },
          
          
         // 插入格式
         var derived = $('#card-derived').val().trim();
        insertFormat: function(type, color) {
        if (derived) variant['衍生卡牌'] = derived;
            const textarea = document.getElementById('card-desc');
            if (!textarea) return;
           
            const start = textarea.selectionStart;
            const end = textarea.selectionEnd;
            const text = textarea.value;
            const selectedText = text.substring(start, end);
           
            const formatted = `{{${type}|${color}|${selectedText}}}`;
            textarea.value = text.substring(0, start) + formatted + text.substring(end);
            textarea.focus();
            textarea.setSelectionRange(start + formatted.length - selectedText.length - 2, start + formatted.length - 2);
        },
          
          
         // 插入换行
         return {
        insertBr: function() {
             name: $('#card-name').val().trim(),
             const textarea = document.getElementById('card-desc');
             variants: [variant]
            if (!textarea) return;
        };
              
    }
            const start = textarea.selectionStart;
   
            const text = textarea.value;
    // 设置表单数据
            textarea.value = text.substring(0, start) + '<br>' + text.substring(start);
    function setFormData(card, variantIndex) {
            textarea.focus();
        variantIndex = variantIndex || 0;
            textarea.setSelectionRange(start + 4, start + 4);
        $('#card-name').val(card.name);
        },
          
          
         // 获取表单数据
         if (variantIndex < card.variants.length) {
        getFormData: function() {
             var variant = card.variants[variantIndex];
             const variant = {};
            var isVariant = variant['卡组'] === '灵光一闪';
              
              
             const art = this.getInputValue('card-art');
             // 设置字段是否可编辑
             if (art) variant.art = art;
            $('#card-name').prop('disabled', isVariant);
            $('#card-art').prop('disabled', isVariant);
            $('.card-dropdown-container').eq(1).find('input').prop('disabled', isVariant);
            $('.card-dropdown-container').eq(2).find('input').prop('disabled', isVariant);
             $('#card-derived').prop('disabled', isVariant);
              
              
             const deck = this.getInputValue('deck-type');
             // 设置值
             if (deck) variant['卡组'] = deck;
            $('#card-art').val(variant.art || '');
              
             $('.card-dropdown-container').eq(0).find('input').val(variant['卡组'] || '');
            const attr = this.getInputValue('card-attr');
             $('.card-dropdown-container').eq(1).find('input').val(variant['属性'] || '');
            if (attr) variant['属性'] = attr;
             $('.card-dropdown-container').eq(2).find('input').val(variant['稀有度'] || '');
              
             $('#card-ap').val(variant.AP !== undefined ? variant.AP : '');
            const rarity = this.getInputValue('card-rarity');
             $('.card-dropdown-container').eq(3).find('input').val(variant['类型'] || '');
            if (rarity) variant['稀有度'] = rarity;
             $('#card-mechanism').val(variant['机制'] || '');
              
             $('#card-desc').val(variant['描述'] || '');
            const ap = this.getInputValue('card-ap');
             $('#card-derived').val(variant['衍生卡牌'] || '');
            if (ap) {
        }
                variant['AP'] = ap.toUpperCase() === 'X' ? 'X' : parseInt(ap);
    }
             }
   
           
    // 清空表单
            const mechanism = this.getInputValue('card-mechanism');
    function clearForm() {
            if (mechanism) variant['机制'] = mechanism;
        $('#card-name').val('').prop('disabled', false);
              
        $('#card-art').val('').prop('disabled', false);
            const cardType = this.getInputValue('card-type');
        $('#card-ap').val('');
            if (cardType) variant['类型'] = cardType;
        $('#card-mechanism').val('');
              
        $('#card-desc').val('');
            const desc = this.getInputValue('card-desc');
        $('#card-derived').val('').prop('disabled', false);
            if (desc) variant['描述'] = desc;
         $('.card-dropdown-input').val('').prop('disabled', false);
              
            const derived = this.getInputValue('card-derived');
            if (derived) variant['衍生卡牌'] = derived;
           
            return {
                name: this.getInputValue('card-name'),
                variants: [variant]
            };
         },
          
          
         // 获取输入值
         cardData.currentCard = null;
        getInputValue: function(id) {
        cardData.currentVariantIndex = null;
            const el = document.getElementById(id);
    }
             return el ? el.value.trim() : '';
   
         },
    // 添加卡牌
    function addCard() {
        var data = getFormData();
        if (!data.name) {
             mw.notify('卡牌名称不能为空!', {type: 'warn'});
            return;
         }
          
          
         // 设置输入值
         cardData.cards.push(data);
         setInputValue: function(id, value) {
        cardData.currentCard = data;
            const el = document.getElementById(id);
        cardData.currentVariantIndex = 0;
            if (el) el.value = value || '';
        updateCardList();
         },
        updateVariantList();
        updateCode();
         clearForm();
        mw.notify('卡牌添加成功!', {type: 'success'});
    }
   
    // 添加变体
    function addVariant() {
        if (!cardData.currentCard) {
            mw.notify('请先选择一个卡牌!', {type: 'warn'});
            return;
         }
          
          
         // 设置表单数据
         var data = getFormData();
        setFormData: function(card, variantIndex = 0) {
        var variant = data.variants[0];
            this.setInputValue('card-name', card.name);
        variant['卡组'] = '灵光一闪';
           
            if (variantIndex < card.variants.length) {
                const variant = card.variants[variantIndex];
                const isVariant = variant['卡组'] === '灵光一闪';
               
                this.toggleVariantFields(isVariant);
               
                this.setInputValue('card-art', variant.art);
                this.setInputValue('deck-type', variant['卡组']);
                this.setInputValue('card-attr', variant['属性']);
                this.setInputValue('card-rarity', variant['稀有度']);
                this.setInputValue('card-ap', variant['AP'] !== undefined ? variant['AP'] : '');
                this.setInputValue('card-mechanism', variant['机制']);
                this.setInputValue('card-type', variant['类型']);
                this.setInputValue('card-desc', variant['描述']);
                this.setInputValue('card-derived', variant['衍生卡牌']);
            }
        },
          
          
         // 清空表单
         cardData.currentCard.variants.push(variant);
        clearForm: function() {
        cardData.currentVariantIndex = cardData.currentCard.variants.length - 1;
            const fields = ['card-name', 'card-art', 'deck-type', 'card-attr', 'card-rarity',
        updateVariantList();
                          'card-ap', 'card-mechanism', 'card-type', 'card-desc', 'card-derived'];
        updateCode();
            fields.forEach(id => this.setInputValue(id, ''));
        mw.notify('变体添加成功!', {type: 'success'});
           
    }
            this.toggleVariantFields(false);
   
            this.currentCard = null;
    // 保存数据
             this.currentVariantIndex = null;
    function saveData() {
         },
        if (!cardData.currentCard || cardData.currentVariantIndex === null) {
            mw.notify('请先选择要保存的卡牌或变体!', {type: 'warn'});
             return;
         }
          
          
         // 添加卡牌
         var data = getFormData();
        addCard: function() {
        var isVariant = cardData.currentVariantIndex > 0;
            const cardData = this.getFormData();
            if (!cardData.name) {
                mw.notify('卡牌名称不能为空!', {type: 'error'});
                return;
            }
           
            this.cards.push(cardData);
            this.currentCard = cardData;
            this.currentVariantIndex = 0;
           
            this.updateCardList();
            this.updateVariantList();
            this.updatePreview();
            this.clearForm();
           
            mw.notify(`卡牌 "${cardData.name}" 添加成功!`, {type: 'success'});
        },
          
          
         // 添加变体
         if (isVariant) {
        addVariant: function() {
             var variant = data.variants[0];
            if (!this.currentCard) {
                mw.notify('请先选择一个卡牌!', {type: 'error'});
                return;
            }
           
            const variantData = this.getFormData();
             const variant = variantData.variants[0];
             variant['卡组'] = '灵光一闪';
             variant['卡组'] = '灵光一闪';
              
             cardData.currentCard.variants[cardData.currentVariantIndex] = variant;
            this.currentCard.variants.push(variant);
        } else {
             this.currentVariantIndex = this.currentCard.variants.length - 1;
             cardData.currentCard.name = data.name;
           
            cardData.currentCard.variants[0] = data.variants[0];
            this.updateVariantList();
        }
            this.updatePreview();
       
           
        updateCardList();
             mw.notify(`为 "${this.currentCard.name}" 添加变体成功!`, {type: 'success'});
        updateVariantList();
         },
        updateCode();
        mw.notify('数据保存成功!', {type: 'success'});
    }
   
    // 删除卡牌
    function deleteCard() {
        if (!cardData.currentCard) {
             mw.notify('请先选择要删除的卡牌!', {type: 'warn'});
            return;
        }
       
        if (!confirm('确定要删除卡牌 "' + cardData.currentCard.name + '" 吗?')) {
            return;
        }
       
        var index = cardData.cards.indexOf(cardData.currentCard);
        if (index > -1) {
            cardData.cards.splice(index, 1);
        }
       
        cardData.currentCard = null;
        cardData.currentVariantIndex = null;
        updateCardList();
        updateVariantList();
        updateCode();
        clearForm();
        mw.notify('卡牌删除成功!', {type: 'success'});
    }
   
    // 删除变体
    function deleteVariant() {
        if (!cardData.currentCard || cardData.currentVariantIndex === null) {
            mw.notify('请先选择要删除的变体!', {type: 'warn'});
            return;
         }
       
        if (cardData.currentVariantIndex === 0) {
            mw.notify('不能删除主卡牌变体!', {type: 'warn'});
            return;
        }
       
        if (!confirm('确定要删除这个变体吗?')) {
            return;
        }
          
          
         // 保存卡牌
         cardData.currentCard.variants.splice(cardData.currentVariantIndex, 1);
         saveCard: function() {
        cardData.currentVariantIndex = 0;
            if (!this.currentCard || this.currentVariantIndex === null) {
        updateVariantList();
                mw.notify('请先选择要保存的卡牌或变体!', {type: 'error'});
         updateCode();
                 return;
        setFormData(cardData.currentCard, 0);
            }
        mw.notify('变体删除成功!', {type: 'success'});
    }
   
    // 更新卡牌列表
    function updateCardList() {
        var list = $('#card-list').empty();
        cardData.cards.forEach(function(card, index) {
            var item = $('<div>')
                .addClass('card-list-item')
                .attr('data-index', index)
                .text(card.name)
                 .click(function() {
                    onCardSelected(index);
                });
              
              
             const cardData = this.getFormData();
             if (cardData.currentCard === card) {
            const isVariant = this.currentVariantIndex > 0;
                 item.addClass('card-list-item-selected');
           
            if (isVariant) {
                 const variant = cardData.variants[0];
                variant['卡组'] = '灵光一闪';
                this.currentCard.variants[this.currentVariantIndex] = variant;
            } else {
                this.currentCard.name = cardData.name;
                this.currentCard.variants[0] = cardData.variants[0];
             }
             }
              
              
             this.updateCardList();
             list.append(item);
            this.updateVariantList();
        });
             this.updatePreview();
    }
              
   
            mw.notify('数据保存成功!', {type: 'success'});
    // 更新变体列表
         },
    function updateVariantList() {
        var list = $('#variant-list').empty();
        if (cardData.currentCard) {
            cardData.currentCard.variants.forEach(function(variant, index) {
                var deck = variant['卡组'] || '未知';
                var text = index === 0 ? '主卡牌 (' + deck + ')' : '变体 ' + index + ' (灵光一闪)';
               
                var item = $('<div>')
                    .addClass('card-list-item')
                    .text(text)
                    .click(function() {
                        onVariantSelected(index);
                    });
               
                if (cardData.currentVariantIndex === index) {
                    item.addClass('card-list-item-selected');
                }
               
                list.append(item);
            });
        }
    }
   
    // 卡牌选择事件
    function onCardSelected(index) {
        cardData.currentCard = cardData.cards[index];
        cardData.currentVariantIndex = 0;
        updateCardList();
        updateVariantList();
        setFormData(cardData.currentCard, 0);
    }
   
    // 变体选择事件
    function onVariantSelected(index) {
        if (!cardData.currentCard) return;
        cardData.currentVariantIndex = index;
        updateVariantList();
        setFormData(cardData.currentCard, index);
    }
   
    // 更新卡牌顺序
    function updateCardOrder() {
        var newCards = [];
        $('#card-list .card-list-item').each(function() {
             var index = $(this).attr('data-index');
             newCards.push(cardData.cards[index]);
        });
        cardData.cards = newCards;
        updateCardList();
        updateCode();
    }
   
    // 转义Lua字符串
    function escapeLuaString(str) {
        if (typeof str !== 'string') return str;
        return str.replace(/\\/g, '\\\\')
                  .replace(/"/g, '\\"')
                  .replace(/\n/g, '\\n');
    }
   
    // 生成Lua代码
    function generateLuaCode() {
        if (cardData.cards.length === 0) {
            return '-- 暂无数据';
         }
          
          
         // 删除卡牌
         var lua = 'local p = {}\n\n';
        deleteCard: function() {
            if (!this.currentCard) {
                mw.notify('请先选择要删除的卡牌!', {type: 'error'});
                return;
            }
           
            if (!confirm(`确定要删除卡牌 "${this.currentCard.name}" 吗?`)) {
                return;
            }
           
            const index = this.cards.indexOf(this.currentCard);
            this.cards.splice(index, 1);
           
            this.currentCard = null;
            this.currentVariantIndex = null;
           
            this.updateCardList();
            this.updateVariantList();
            this.updatePreview();
            this.clearForm();
           
            mw.notify('卡牌删除成功!', {type: 'success'});
        },
          
          
         // 删除变体
         // 生成 cardOrder(不包含衍生卡牌)
         deleteVariant: function() {
         lua += 'local cardOrder = {\n';
             if (!this.currentCard || this.currentVariantIndex === null) {
        cardData.cards.forEach(function(card) {
                 mw.notify('请先选择要删除的变体!', {type: 'error'});
             if (card.variants[0] && card.variants[0]['卡组'] !== '衍生卡牌') {
                return;
                 lua += '   "' + escapeLuaString(card.name) + '",\n';
            }
           
            if (this.currentVariantIndex === 0) {
                mw.notify('不能删除主卡牌变体!', {type: 'error'});
                return;
             }
             }
           
        });
            if (!confirm('确定要删除这个变体吗?')) {
        lua += '}\n\n';
                return;
            }
           
            this.currentCard.variants.splice(this.currentVariantIndex, 1);
            this.currentVariantIndex = 0;
           
            this.updateVariantList();
            this.updatePreview();
            this.setFormData(this.currentCard, 0);
           
            mw.notify('变体删除成功!', {type: 'success'});
        },
          
          
         // 选择卡牌
         // 生成 card 数据
         selectCard: function(index) {
         lua += 'local card = {\n';
            this.currentCard = this.cards[index];
            this.currentVariantIndex = 0;
            this.updateVariantList();
            this.setFormData(this.currentCard, 0);
        },
          
          
         // 选择变体
         cardData.cards.forEach(function(card) {
        selectVariant: function(index) {
             lua += '   ["' + escapeLuaString(card.name) + '"] = {\n';
            if (!this.currentCard) return;
            this.currentVariantIndex = index;
            this.setFormData(this.currentCard, index);
        },
       
        // 更新卡牌列表
        updateCardList: function() {
             const list = document.getElementById('card-list');
            if (!list) return;
              
              
             list.innerHTML = '';
             card.variants.forEach(function(variant) {
           
                 lua += '       {\n';
            this.cards.forEach((card, index) => {
                 const item = document.createElement('div');
                item.className = 'cm-card-item';
                item.setAttribute('data-index', index);
                item.textContent = card.name;
                  
                  
                 if (this.currentCard === card) {
                 // 按固定顺序输出字段
                    item.classList.add('cm-active');
                fieldDefinitions.cardOrder.forEach(function(field) {
                 }
                    if (variant.hasOwnProperty(field) && variant[field] !== null && variant[field] !== '') {
                        var value = variant[field];
                        if (typeof value === 'string') {
                            lua += '            ["' + field + '"] = "' + escapeLuaString(value) + '",\n';
                        } else if (typeof value === 'number') {
                            lua += '            ["' + field + '"] = ' + value + ',\n';
                        }
                    }
                 });
                  
                  
                 list.appendChild(item);
                 lua += '        },\n';
             });
             });
         },
           
            lua += '    },\n';
         });
          
          
         // 更新变体列表
         lua += '}\n\n';
         updateVariantList: function() {
        lua += 'p.card = card\n';
            const list = document.getElementById('variant-list');
        lua += 'p.cardOrder = cardOrder\n\n';
             if (!list) return;
        lua += 'return p\n';
       
        return lua;
    }
   
    // 更新代码显示
    function updateCode() {
        var code = generateLuaCode();
         $('#code-display').val(code);
    }
   
    // 复制代码
    function copyCode() {
        var code = $('#code-display');
        code.select();
        document.execCommand('copy');
        mw.notify('代码已复制到剪贴板!', {type: 'success'});
    }
   
    // 从Wiki加载数据
    function loadFromWiki() {
        mw.notify('正在加载数据...', {type: 'info'});
       
        // 获取所有模块:卡牌/开头的页面
        new mw.Api().get({
            action: 'query',
            list: 'allpages',
            apprefix: '卡牌/',
            apnamespace: 828, // Module namespace
            aplimit: 500
        }).done(function(data) {
             if (!data.query || !data.query.allpages || data.query.allpages.length === 0) {
                mw.notify('未找到卡牌模块!', {type: 'warn'});
                return;
            }
              
              
             list.innerHTML = '';
             var pages = data.query.allpages;
            var loadedCards = [];
            var loadCount = 0;
              
              
             if (this.currentCard) {
             pages.forEach(function(page) {
                 this.currentCard.variants.forEach((variant, index) => {
                 var pageName = page.title;
                     const deck = variant['卡组'] || '未知';
               
                     const label = index === 0 ? `主卡牌 (${deck})` : `变体 ${index} (灵光一闪)`;
                // 加载每个模块的内容
                new mw.Api().get({
                    action: 'query',
                     prop: 'revisions',
                    titles: pageName,
                    rvprop: 'content',
                     rvslots: 'main'
                }).done(function(moduleData) {
                    loadCount++;
                      
                      
                     const item = document.createElement('div');
                     var pageId = Object.keys(moduleData.query.pages)[0];
                     item.className = 'cm-variant-item';
                     var content = moduleData.query.pages[pageId].revisions[0].slots.main['*'];
                    item.setAttribute('data-index', index);
                    item.textContent = label;
                      
                      
                     if (this.currentVariantIndex === index) {
                    // 解析Lua内容
                         item.classList.add('cm-active');
                    var parsed = parseLuaContent(content);
                     if (parsed && parsed.length > 0) {
                         loadedCards = loadedCards.concat(parsed);
                     }
                     }
                      
                      
                     list.appendChild(item);
                     // 所有页面加载完成
                    if (loadCount === pages.length) {
                        cardData.cards = loadedCards;
                        cardData.currentCard = null;
                        cardData.currentVariantIndex = null;
                        updateCardList();
                        updateVariantList();
                        updateCode();
                        clearForm();
                        mw.notify('成功加载 ' + loadedCards.length + ' 张卡牌!', {type: 'success'});
                    }
                 });
                 });
             }
             });
         },
         }).fail(function() {
            mw.notify('加载失败!', {type: 'error'});
        });
    }
   
    // 解析Lua内容
    function parseLuaContent(content) {
        var cards = [];
          
          
         // 生成Lua代码
         try {
        generateLuaCode: function() {
            // 提取 cardOrder
             if (this.cards.length === 0) {
            var cardOrderMatch = content.match(/local\s+cardOrder\s*=\s*\{([^}]+)\}/s);
                return '-- 暂无数据';
            var cardOrder = [];
             if (cardOrderMatch) {
                var orderContent = cardOrderMatch[1];
                var nameMatches = orderContent.match(/"([^"]+)"/g);
                if (nameMatches) {
                    cardOrder = nameMatches.map(function(m) { return m.slice(1, -1); });
                }
             }
             }
              
              
             let lua = 'local p = {}\n\n';
             // 提取 card 表
            var cardTableMatch = content.match(/local\s+card\s*=\s*\{(.+)\}\s*p\.card/s);
            if (!cardTableMatch) return cards;
              
              
             // cardOrder
            var cardContent = cardTableMatch[1];
             lua += 'local cardOrder = {\n';
           
             this.cards.forEach(card => {
             // 提取所有卡牌名称
                 if (card.variants[0] && card.variants[0]['卡组'] !== '衍生卡牌') {
            var allCardNames = [];
                     lua += `    "${this.escapeLua(card.name)}",\n`;
             var namePattern = /\["([^"]+)"\]\s*=\s*\{/g;
            var match;
             while ((match = namePattern.exec(cardContent)) !== null) {
                var name = match[1];
                 if (allCardNames.indexOf(name) === -1) {
                    allCardNames.push(name);
                }
            }
           
            // 合并cardOrder和实际卡牌名称
            var finalCardNames = [];
            cardOrder.forEach(function(name) {
                if (allCardNames.indexOf(name) !== -1) {
                     finalCardNames.push(name);
                    allCardNames.splice(allCardNames.indexOf(name), 1);
                 }
                 }
             });
             });
             lua += '}\n\n';
             finalCardNames = finalCardNames.concat(allCardNames);
              
              
             // card data
             // 解析每个卡牌
             lua += 'local card = {\n';
             finalCardNames.forEach(function(cardName) {
            this.cards.forEach(card => {
                 var variants = extractCardVariants(cardContent, cardName);
                 lua += `    ["${this.escapeLua(card.name)}"] = {\n`;
                 if (variants.length > 0) {
                  
                     cards.push({
                card.variants.forEach(variant => {
                         name: cardName,
                     lua += '        {\n';
                         variants: variants
                   
                    const fieldOrder = ['art', '卡组', '属性', '稀有度', 'AP', '机制', '类型', '描述', '衍生卡牌'];
                   
                    fieldOrder.forEach(field => {
                         if (variant[field] !== undefined && variant[field] !== '') {
                            const value = variant[field];
                            if (typeof value === 'string') {
                                lua += `            ["${field}"] = "${this.escapeLua(value)}",\n`;
                            } else {
                                lua += `            ["${field}"] = ${value},\n`;
                            }
                         }
                     });
                     });
                   
                 }
                    lua += '        },\n';
                });
               
                 lua += '    },\n';
             });
             });
            lua += '}\n\n';
              
              
             lua += 'p.card = card\n';
        } catch (e) {
            lua += 'p.cardOrder = cardOrder\n\n';
             console.error('解析错误:', e);
            lua += 'return p\n';
        }
           
       
            return lua;
        return cards;
        },
    }
   
    // 提取卡牌变体
    function extractCardVariants(content, cardName) {
        var variants = [];
        var escapedName = cardName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        var pattern = new RegExp('\\["' + escapedName + '"\\]\\s*=\\s*\\{', 'g');
        var match = pattern.exec(content);
       
        if (!match) return variants;
          
          
         // 转义Lua字符串
         var startPos = match.index + match[0].length;
        escapeLua: function(str) {
        var cardBlock = extractBalancedBraces(content, startPos);
            if (typeof str !== 'string') return str;
            return str.replace(/\\/g, '\\\\')
                      .replace(/"/g, '\\"')
                      .replace(/\n/g, '\\n');
        },
          
          
         // 更新预览
         if (!cardBlock) return variants;
        updatePreview: function() {
            const code = this.generateLuaCode();
            const preview = document.getElementById('code-preview');
            if (preview) preview.textContent = code;
        },
          
          
         // 导出到模块
         // 解析所有变体
         exportToModule: function() {
         var pos = 0;
             if (this.cards.length === 0) {
        while (pos < cardBlock.length) {
                 mw.notify('没有数据可导出!', {type: 'error'});
            while (pos < cardBlock.length && /\s/.test(cardBlock[pos])) pos++;
                 return;
             if (pos >= cardBlock.length) break;
           
            if (cardBlock[pos] === '{') {
                 var variantContent = extractBalancedBraces(cardBlock, pos + 1);
                if (variantContent) {
                    var variant = parseVariant(variantContent);
                    if (Object.keys(variant).length > 0) {
                        variants.push(variant);
                    }
                    pos += variantContent.length + 2;
                } else {
                    pos++;
                 }
            } else {
                pos++;
             }
             }
        }
       
        return variants;
    }
   
    // 提取平衡的大括号内容
    function extractBalancedBraces(text, startPos) {
        var braceCount = 1;
        var pos = startPos;
        var inString = false;
        var escapeNext = false;
        var result = [];
       
        while (pos < text.length && braceCount > 0) {
            var char = text[pos];
              
              
             const code = this.generateLuaCode();
             if (escapeNext) {
             const moduleName = `模块:卡牌/${this.characterName}`;
                result.push(char);
                escapeNext = false;
                pos++;
                continue;
             }
              
              
             new mw.Api().postWithToken('csrf', {
             if (char === '\\' && inString) {
                action: 'edit',
                 result.push(char);
                title: moduleName,
                escapeNext = true;
                text: code,
                 pos++;
                summary: '更新卡牌数据',
                continue;
                contentmodel: 'Scribunto'
            }
            }).done(() => {
                 mw.notify(`成功保存到 ${moduleName}`, {type: 'success'});
            }).fail((err) => {
                 mw.notify('保存失败: ' + err, {type: 'error'});
            });
        },
       
        // 从模块导入
        importFromModule: function() {
            const moduleName = prompt('请输入要导入的模块名称(如:妮雅):');
            if (!moduleName) return;
              
              
             this.loadCardModule(moduleName);
             if (char === '"') {
        },
                inString = !inString;
       
                result.push(char);
        // 加载卡牌模块
                pos++;
        loadCardModule: function(characterName) {
                continue;
            const name = characterName || this.characterName;
             }
             if (!name) return;
              
              
             const moduleName = `模块:卡牌/${name}`;
             if (!inString) {
                if (char === '{') {
                    braceCount++;
                } else if (char === '}') {
                    braceCount--;
                    if (braceCount === 0) break;
                }
            }
              
              
             new mw.Api().get({
             result.push(char);
                action: 'query',
            pos++;
                prop: 'revisions',
        }
                titles: moduleName,
       
                rvprop: 'content',
        return braceCount === 0 ? result.join('') : null;
                rvslots: 'main'
    }
            }).done((data) => {
   
                const pages = data.query.pages;
    // 解析变体
                const page = pages[Object.keys(pages)[0]];
    function parseVariant(content) {
               
        var variant = {};
                if (page.revisions) {
        var pos = 0;
                    const content = page.revisions[0].slots.main['*'];
                    this.parseLuaCode(content);
                    mw.notify(`成功从 ${moduleName} 导入数据`, {type: 'success'});
                } else {
                    mw.notify('模块不存在', {type: 'error'});
                }
            }).fail(() => {
                mw.notify('加载失败', {type: 'error'});
            });
        },
          
          
         // 解析Lua代码
         while (pos < content.length) {
        parseLuaCode: function(content) {
            while (pos < content.length && /[\s,]/.test(content[pos])) pos++;
             try {
            if (pos >= content.length) break;
                this.cards = [];
              
                  
            if (content[pos] === '[') {
                const orderMatch = content.match(/local\s+cardOrder\s*=\s*\{([^}]+)\}/s);
                 var fieldMatch = content.substring(pos).match(/\["([^"]+)"\]\s*=\s*/);
                const cardOrder = [];
                 if (fieldMatch) {
                 if (orderMatch) {
                     var fieldName = fieldMatch[1];
                     const names = orderMatch[1].match(/"([^"]+)"/g);
                    pos += fieldMatch[0].length;
                     if (names) {
                   
                         names.forEach(name => {
                    var result = extractFieldValue(content, pos);
                            cardOrder.push(name.replace(/"/g, ''));
                     if (result.value !== null) {
                         });
                         variant[fieldName] = result.value;
                        pos += result.length;
                    } else {
                         pos++;
                     }
                     }
                } else {
                    pos++;
                 }
                 }
               
            } else {
                const cardMatch = content.match(/local\s+card\s*=\s*\{(.+)\}\s*p\.card/s);
                 pos++;
                if (!cardMatch) {
                    mw.notify('无法解析卡牌数据', {type: 'error'});
                    return;
                 }
               
                const cardContent = cardMatch[1];
                const cardPattern = /\["([^"]+)"\]\s*=\s*\{/g;
                let match;
                const allCardNames = [];
               
                while ((match = cardPattern.exec(cardContent)) !== null) {
                    const cardName = match[1];
                    if (!allCardNames.includes(cardName)) {
                        allCardNames.push(cardName);
                    }
                }
               
                const sortedNames = [];
                cardOrder.forEach(name => {
                    if (allCardNames.includes(name)) {
                        sortedNames.push(name);
                        allCardNames.splice(allCardNames.indexOf(name), 1);
                    }
                });
                sortedNames.push(...allCardNames);
               
                sortedNames.forEach(cardName => {
                    const variants = this.extractCardVariants(cardContent, cardName);
                    if (variants.length > 0) {
                        this.cards.push({
                            name: cardName,
                            variants: variants
                        });
                    }
                });
               
                this.updateCardList();
                this.updateVariantList();
                this.updatePreview();
                this.clearForm();
               
            } catch (e) {
                console.error('解析错误:', e);
                mw.notify('解析失败: ' + e.message, {type: 'error'});
             }
             }
         },
         }
       
        return variant;
    }
   
    // 提取字段值
    function extractFieldValue(text, startPos) {
        var pos = startPos;
          
          
         extractCardVariants: function(content, cardName) {
         while (pos < text.length && /\s/.test(text[pos])) pos++;
            const variants = [];
        if (pos >= text.length) return {value: null, length: 0};
            const escapedName = cardName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
       
             const pattern = new RegExp(`\\["${escapedName}"\\]\\s*=\\s*\\{`, 'g');
        // 字符串值
             const match = pattern.exec(content);
        if (text[pos] === '"') {
            pos++;
             var valueChars = [];
             var escapeNext = false;
              
              
            if (!match) return variants;
             while (pos < text.length) {
           
                 var char = text[pos];
            let pos = match.index + match[0].length;
            let braceCount = 1;
            let variantStart = -1;
            let inString = false;
            let escape = false;
           
             while (pos < content.length && braceCount > 0) {
                 const char = content[pos];
                  
                  
                 if (escape) {
                 if (escapeNext) {
                     escape = false;
                     if (char === 'n') valueChars.push('\n');
                    else if (char === 't') valueChars.push('\t');
                    else if (char === '\\') valueChars.push('\\');
                    else if (char === '"') valueChars.push('"');
                    else valueChars.push(char);
                    escapeNext = false;
                     pos++;
                     pos++;
                     continue;
                     continue;
                 }
                 }
                  
                  
                 if (char === '\\' && inString) {
                 if (char === '\\') {
                     escape = true;
                     escapeNext = true;
                     pos++;
                     pos++;
                     continue;
                     continue;
第748行: 第846行:
                  
                  
                 if (char === '"') {
                 if (char === '"') {
                     inString = !inString;
                     pos++;
                    break;
                 }
                 }
                  
                  
                 if (!inString) {
                 valueChars.push(char);
                    if (char === '{') {
                pos++;
                        if (braceCount === 1 && variantStart === -1) {
            }
                            variantStart = pos + 1;
           
                        }
            return {
                        braceCount++;
                value: valueChars.join(''),
                    } else if (char === '}') {
                length: pos - startPos
                        braceCount--;
            };
                        if (braceCount === 1 && variantStart !== -1) {
        }
                            const variantContent = content.substring(variantStart, pos);
        // 数字或其他值
                            const variant = this.parseVariant(variantContent);
        else {
                            variants.push(variant);
            var valueMatch = text.substring(pos).match(/([^,\n}\]]+)/);
                            variantStart = -1;
            if (valueMatch) {
                        }
                var valueStr = valueMatch[1].trim();
                     }
                var length = valueMatch[0].length;
               
                if (/^\d+$/.test(valueStr) || /^-\d+$/.test(valueStr)) {
                    return {value: parseInt(valueStr), length: length};
                } else {
                     return {value: valueStr, length: length};
                 }
                 }
               
            }
                pos++;
        }
       
        return {value: null, length: 0};
    }
   
    // 保存到Wiki
    function saveToWiki() {
        if (cardData.cards.length === 0) {
            mw.notify('没有数据可保存!', {type: 'warn'});
            return;
        }
       
        if (!confirm('确定要保存数据到Wiki吗?这将覆盖现有的模块页面!')) {
            return;
        }
       
        mw.notify('正在保存数据...', {type: 'info'});
       
        // 按角色名分组卡牌
        var groupedCards = {};
        cardData.cards.forEach(function(card) {
            // 这里需要用户手动指定角色名,简化处理,可以提示用户
            // 暂时使用第一个卡牌的art文件名推测角色
            var characterName = prompt('请为卡牌 "' + card.name + '" 指定角色名:', '');
            if (!characterName) {
                characterName = '未分类';
             }
             }
              
              
             return variants;
             if (!groupedCards[characterName]) {
         },
                groupedCards[characterName] = [];
            }
            groupedCards[characterName].push(card);
         });
          
          
         parseVariant: function(content) {
         // 保存每个角色的模块
            const variant = {};
        var saveCount = 0;
            const fieldPattern = /\["([^"]+)"\]\s*=\s*("([^"\\]*(\\.[^"\\]*)*)"|(-?\d+|[XxA-Za-z]+))/g;
        var totalModules = Object.keys(groupedCards).length;
             let match;
       
        Object.keys(groupedCards).forEach(function(characterName) {
            var cards = groupedCards[characterName];
            var luaCode = generateLuaCodeForCharacter(cards);
             var pageName = '模块:卡牌/' + characterName;
              
              
             while ((match = fieldPattern.exec(content)) !== null) {
             new mw.Api().postWithToken('csrf', {
                 const fieldName = match[1];
                action: 'edit',
                 let value;
                title: pageName,
                text: luaCode,
                summary: '通过卡牌编辑器更新',
                contentmodel: 'Scribunto'
            }).done(function() {
                saveCount++;
                if (saveCount === totalModules) {
                    mw.notify('所有数据保存成功!', {type: 'success'});
                }
            }).fail(function() {
                mw.notify('保存 ' + pageName + ' 失败!', {type: 'error'});
            });
        });
    }
   
    // 为特定角色生成Lua代码
    function generateLuaCodeForCharacter(cards) {
        var lua = 'local p = {}\n\n';
       
        lua += 'local cardOrder = {\n';
        cards.forEach(function(card) {
            if (card.variants[0] && card.variants[0]['卡组'] !== '衍生卡牌') {
                 lua += '    "' + escapeLuaString(card.name) + '",\n';
            }
        });
        lua += '}\n\n';
       
        lua += 'local card = {\n';
        cards.forEach(function(card) {
            lua += '    ["' + escapeLuaString(card.name) + '"] = {\n';
           
            card.variants.forEach(function(variant) {
                 lua += '        {\n';
                  
                  
                 if (match[2].startsWith('"')) {
                 fieldDefinitions.cardOrder.forEach(function(field) {
                    value = match[3]
                    if (variant.hasOwnProperty(field) && variant[field] !== null && variant[field] !== '') {
                         .replace(/\\"/g, '"')
                        var value = variant[field];
                        .replace(/\\\\/g, '\\')
                         if (typeof value === 'string') {
                        .replace(/\\n/g, '\n');
                            lua += '            ["' + field + '"] = "' + escapeLuaString(value) + '",\n';
                } else {
                        } else if (typeof value === 'number') {
                    const val = match[5];
                            lua += '            ["' + field + '"] = ' + value + ',\n';
                    if (/^-?\d+$/.test(val)) {
                        }
                        value = parseInt(val);
                    } else {
                        value = val;
                     }
                     }
                 }
                 });
                  
                  
                 variant[fieldName] = value;
                 lua += '        },\n';
             }
             });
              
              
             return variant;
             lua += '    },\n';
         }
        });
     };
        lua += '}\n\n';
       
        lua += 'p.card = card\n';
        lua += 'p.cardOrder = cardOrder\n\n';
        lua += 'return p\n';
          
        return lua;
     }
      
      
     mw.loader.using(['mediawiki.api', 'mediawiki.notify']).then(() => {
     // 初始化
         if (mw.config.get('wgPageName') === 'MediaWiki:Card') {
    $(function() {
            CardManager.init();
         initUI();
        }
     });
     });
      
      
    window.CardManager = CardManager;
})();
})();

2025年10月2日 (四) 10:32的版本

// MediaWiki:Card.js
// 卡牌管理系统

(function() {
    'use strict';
    
    // 检查是否在正确的页面
    if (mw.config.get('wgPageName') !== 'MediaWiki:Card') {
        return;
    }
    
    // 卡牌数据存储
    var cardData = {
        cards: [],
        currentCard: null,
        currentVariantIndex: null
    };
    
    // 字段定义
    var fieldDefinitions = {
        cardOrder: ['art', '卡组', '属性', '稀有度', 'AP', '机制', '类型', '描述', '衍生卡牌'],
        deckTypes: ['', '起始卡牌', '独特卡牌', '灵光一闪', '衍生卡牌', '神光一闪'],
        attributes: ['', '热情', '秩序', '正义', '本能', '虚无'],
        rarities: ['', '白', '蓝', '橙', '彩'],
        types: ['', '攻击', '技能', '强化', '状态异常']
    };
    
    // 创建下拉选择框
    function createDropdown(options, value, placeholder) {
        var container = $('<div>').addClass('card-dropdown-container');
        var input = $('<input>')
            .addClass('card-dropdown-input')
            .attr('placeholder', placeholder || '点击选择或输入...')
            .val(value || '');
        
        var dropdown = $('<div>').addClass('card-dropdown-list').hide();
        
        options.forEach(function(opt) {
            $('<div>')
                .addClass('card-dropdown-item')
                .text(opt || '(空)')
                .click(function() {
                    input.val(opt);
                    dropdown.hide();
                })
                .appendTo(dropdown);
        });
        
        input.on('focus click', function(e) {
            e.stopPropagation();
            $('.card-dropdown-list').hide();
            dropdown.show();
        });
        
        $(document).click(function() {
            dropdown.hide();
        });
        
        container.append(input, dropdown);
        return container;
    }
    
    // 创建表单字段
    function createFormField(label, inputElement) {
        return $('<div>').addClass('card-form-field')
            .append($('<div>').addClass('card-form-label').text(label))
            .append($('<div>').addClass('card-form-input').append(inputElement));
    }
    
    // 初始化界面
    function initUI() {
        var container = $('<div>').attr('id', 'card-editor-container');
        
        // 左侧:输入区
        var leftPanel = $('<div>').addClass('card-panel card-input-panel');
        var formGroup = $('<div>').addClass('card-group').append($('<div>').addClass('card-group-title').text('卡牌数据'));
        
        // 创建表单字段
        var nameInput = $('<input>').attr('id', 'card-name').attr('placeholder', '请输入卡牌名称...');
        formGroup.append(createFormField('卡牌名称:', nameInput));
        
        var deckDropdown = createDropdown(fieldDefinitions.deckTypes, '', '点击选择或输入...');
        formGroup.append(createFormField('卡组类型:', deckDropdown));
        
        var artContainer = $('<div>').addClass('card-art-container');
        var artInput = $('<input>').attr('id', 'card-art').attr('placeholder', '输入图片文件名...');
        artContainer.append(artInput);
        formGroup.append(createFormField('图片文件:', artContainer));
        
        var attrDropdown = createDropdown(fieldDefinitions.attributes, '', '点击选择...');
        formGroup.append(createFormField('属性:', attrDropdown));
        
        var rarityDropdown = createDropdown(fieldDefinitions.rarities, '', '点击选择...');
        formGroup.append(createFormField('稀有度:', rarityDropdown));
        
        var apInput = $('<input>').attr('id', 'card-ap').attr('placeholder', '输入AP数值...');
        formGroup.append(createFormField('AP (行动点):', apInput));
        
        var typeDropdown = createDropdown(fieldDefinitions.types, '', '点击选择...');
        formGroup.append(createFormField('卡牌类型:', typeDropdown));
        
        var mechanismInput = $('<input>').attr('id', 'card-mechanism').attr('placeholder', '请输入卡牌机制...');
        formGroup.append(createFormField('卡牌机制:', mechanismInput));
        
        // 描述区域
        var descContainer = $('<div>').addClass('card-desc-container');
        var descHeader = $('<div>').addClass('card-desc-header')
            .append($('<span>').text('卡牌描述:'))
            .append($('<div>').addClass('card-desc-buttons')
                .append($('<div>').addClass('card-button card-button-small card-button-blue').text('蓝色文本').click(function() { insertTextFormat('蓝'); }))
                .append($('<div>').addClass('card-button card-button-small card-button-green').text('绿色文本').click(function() { insertTextFormat('绿'); }))
                .append($('<div>').addClass('card-button card-button-small card-button-stroke').text('绿色描边').click(insertStrokeFormat))
                .append($('<div>').addClass('card-button card-button-small card-button-br').text('插入换行').click(insertBr))
            );
        
        var descTextarea = $('<textarea>').attr('id', 'card-desc').attr('placeholder', '请输入卡牌描述...');
        descContainer.append(descHeader, descTextarea);
        formGroup.append(descContainer);
        
        var derivedInput = $('<input>').attr('id', 'card-derived').attr('placeholder', '请输入衍生卡牌...');
        formGroup.append(createFormField('衍生卡牌:', derivedInput));
        
        leftPanel.append(formGroup);
        
        // 按钮区
        var buttonContainer = $('<div>').addClass('card-button-container');
        buttonContainer.append(
            $('<div>').addClass('card-button card-button-add').text('添加卡牌').click(addCard),
            $('<div>').addClass('card-button card-button-add').text('添加变体').click(addVariant),
            $('<div>').addClass('card-button').text('保存数据').click(saveData),
            $('<div>').addClass('card-button').text('清空表单').click(clearForm)
        );
        leftPanel.append(buttonContainer);
        
        // 中间:列表区
        var middlePanel = $('<div>').addClass('card-panel card-list-panel');
        
        var cardListGroup = $('<div>').addClass('card-group')
            .append($('<div>').addClass('card-group-title').text('卡牌列表'))
            .append($('<div>').attr('id', 'card-list').addClass('card-list'));
        middlePanel.append(cardListGroup);
        
        var variantListGroup = $('<div>').addClass('card-group')
            .append($('<div>').addClass('card-group-title').text('变体列表'))
            .append($('<div>').attr('id', 'variant-list').addClass('card-list'));
        middlePanel.append(variantListGroup);
        
        var deleteButtons = $('<div>').addClass('card-button-container');
        deleteButtons.append(
            $('<div>').addClass('card-button card-button-delete').text('删除卡牌').click(deleteCard),
            $('<div>').addClass('card-button card-button-delete').text('删除变体').click(deleteVariant)
        );
        middlePanel.append(deleteButtons);
        
        // 右侧:代码显示区
        var rightPanel = $('<div>').addClass('card-panel card-code-panel');
        
        var codeGroup = $('<div>').addClass('card-group')
            .append($('<div>').addClass('card-group-title').text('Lua代码预览'))
            .append($('<textarea>').attr('id', 'code-display').addClass('card-code-display').attr('readonly', true));
        rightPanel.append(codeGroup);
        
        var codeButtons = $('<div>').addClass('card-button-container');
        codeButtons.append(
            $('<div>').addClass('card-button').text('复制代码').click(copyCode),
            $('<div>').addClass('card-button').text('加载数据').click(loadFromWiki),
            $('<div>').addClass('card-button').text('保存到Wiki').click(saveToWiki)
        );
        rightPanel.append(codeButtons);
        
        container.append(leftPanel, middlePanel, rightPanel);
        $('#mw-content-text').empty().append(container);
        
        // 初始化拖拽排序
        initSortable();
    }
    
    // 初始化拖拽排序
    function initSortable() {
        mw.loader.using('jquery.ui', function() {
            $('#card-list').sortable({
                update: function(event, ui) {
                    updateCardOrder();
                }
            });
        });
    }
    
    // 文本格式化函数
    function insertTextFormat(color) {
        var textarea = $('#card-desc')[0];
        var start = textarea.selectionStart;
        var end = textarea.selectionEnd;
        var text = textarea.value;
        var selectedText = text.substring(start, end);
        
        var newText = text.substring(0, start) + 
                      '{{文本|' + color + '|' + selectedText + '}}' + 
                      text.substring(end);
        
        textarea.value = newText;
        textarea.focus();
        textarea.setSelectionRange(start + 6 + color.length, start + 6 + color.length + selectedText.length);
    }
    
    function insertStrokeFormat() {
        var textarea = $('#card-desc')[0];
        var start = textarea.selectionStart;
        var end = textarea.selectionEnd;
        var text = textarea.value;
        var selectedText = text.substring(start, end);
        
        var newText = text.substring(0, start) + 
                      '{{描边|绿|' + selectedText + '}}' + 
                      text.substring(end);
        
        textarea.value = newText;
        textarea.focus();
        textarea.setSelectionRange(start + 7, start + 7 + selectedText.length);
    }
    
    function insertBr() {
        var textarea = $('#card-desc')[0];
        var pos = textarea.selectionStart;
        var text = textarea.value;
        
        var newText = text.substring(0, pos) + '<br>' + text.substring(pos);
        textarea.value = newText;
        textarea.focus();
        textarea.setSelectionRange(pos + 4, pos + 4);
    }
    
    // 获取表单数据
    function getFormData() {
        var variant = {};
        
        var art = $('#card-art').val().trim();
        if (art) variant.art = art;
        
        var deck = $('.card-dropdown-container').eq(0).find('input').val().trim();
        if (deck) variant['卡组'] = deck;
        
        var attr = $('.card-dropdown-container').eq(1).find('input').val().trim();
        if (attr) variant['属性'] = attr;
        
        var rarity = $('.card-dropdown-container').eq(2).find('input').val().trim();
        if (rarity) variant['稀有度'] = rarity;
        
        var ap = $('#card-ap').val().trim();
        if (ap) {
            variant.AP = isNaN(ap) ? ap : parseInt(ap);
        }
        
        var type = $('.card-dropdown-container').eq(3).find('input').val().trim();
        if (type) variant['类型'] = type;
        
        var mechanism = $('#card-mechanism').val().trim();
        if (mechanism) variant['机制'] = mechanism;
        
        var desc = $('#card-desc').val().trim();
        if (desc) variant['描述'] = desc;
        
        var derived = $('#card-derived').val().trim();
        if (derived) variant['衍生卡牌'] = derived;
        
        return {
            name: $('#card-name').val().trim(),
            variants: [variant]
        };
    }
    
    // 设置表单数据
    function setFormData(card, variantIndex) {
        variantIndex = variantIndex || 0;
        $('#card-name').val(card.name);
        
        if (variantIndex < card.variants.length) {
            var variant = card.variants[variantIndex];
            var isVariant = variant['卡组'] === '灵光一闪';
            
            // 设置字段是否可编辑
            $('#card-name').prop('disabled', isVariant);
            $('#card-art').prop('disabled', isVariant);
            $('.card-dropdown-container').eq(1).find('input').prop('disabled', isVariant);
            $('.card-dropdown-container').eq(2).find('input').prop('disabled', isVariant);
            $('#card-derived').prop('disabled', isVariant);
            
            // 设置值
            $('#card-art').val(variant.art || '');
            $('.card-dropdown-container').eq(0).find('input').val(variant['卡组'] || '');
            $('.card-dropdown-container').eq(1).find('input').val(variant['属性'] || '');
            $('.card-dropdown-container').eq(2).find('input').val(variant['稀有度'] || '');
            $('#card-ap').val(variant.AP !== undefined ? variant.AP : '');
            $('.card-dropdown-container').eq(3).find('input').val(variant['类型'] || '');
            $('#card-mechanism').val(variant['机制'] || '');
            $('#card-desc').val(variant['描述'] || '');
            $('#card-derived').val(variant['衍生卡牌'] || '');
        }
    }
    
    // 清空表单
    function clearForm() {
        $('#card-name').val('').prop('disabled', false);
        $('#card-art').val('').prop('disabled', false);
        $('#card-ap').val('');
        $('#card-mechanism').val('');
        $('#card-desc').val('');
        $('#card-derived').val('').prop('disabled', false);
        $('.card-dropdown-input').val('').prop('disabled', false);
        
        cardData.currentCard = null;
        cardData.currentVariantIndex = null;
    }
    
    // 添加卡牌
    function addCard() {
        var data = getFormData();
        if (!data.name) {
            mw.notify('卡牌名称不能为空!', {type: 'warn'});
            return;
        }
        
        cardData.cards.push(data);
        cardData.currentCard = data;
        cardData.currentVariantIndex = 0;
        updateCardList();
        updateVariantList();
        updateCode();
        clearForm();
        mw.notify('卡牌添加成功!', {type: 'success'});
    }
    
    // 添加变体
    function addVariant() {
        if (!cardData.currentCard) {
            mw.notify('请先选择一个卡牌!', {type: 'warn'});
            return;
        }
        
        var data = getFormData();
        var variant = data.variants[0];
        variant['卡组'] = '灵光一闪';
        
        cardData.currentCard.variants.push(variant);
        cardData.currentVariantIndex = cardData.currentCard.variants.length - 1;
        updateVariantList();
        updateCode();
        mw.notify('变体添加成功!', {type: 'success'});
    }
    
    // 保存数据
    function saveData() {
        if (!cardData.currentCard || cardData.currentVariantIndex === null) {
            mw.notify('请先选择要保存的卡牌或变体!', {type: 'warn'});
            return;
        }
        
        var data = getFormData();
        var isVariant = cardData.currentVariantIndex > 0;
        
        if (isVariant) {
            var variant = data.variants[0];
            variant['卡组'] = '灵光一闪';
            cardData.currentCard.variants[cardData.currentVariantIndex] = variant;
        } else {
            cardData.currentCard.name = data.name;
            cardData.currentCard.variants[0] = data.variants[0];
        }
        
        updateCardList();
        updateVariantList();
        updateCode();
        mw.notify('数据保存成功!', {type: 'success'});
    }
    
    // 删除卡牌
    function deleteCard() {
        if (!cardData.currentCard) {
            mw.notify('请先选择要删除的卡牌!', {type: 'warn'});
            return;
        }
        
        if (!confirm('确定要删除卡牌 "' + cardData.currentCard.name + '" 吗?')) {
            return;
        }
        
        var index = cardData.cards.indexOf(cardData.currentCard);
        if (index > -1) {
            cardData.cards.splice(index, 1);
        }
        
        cardData.currentCard = null;
        cardData.currentVariantIndex = null;
        updateCardList();
        updateVariantList();
        updateCode();
        clearForm();
        mw.notify('卡牌删除成功!', {type: 'success'});
    }
    
    // 删除变体
    function deleteVariant() {
        if (!cardData.currentCard || cardData.currentVariantIndex === null) {
            mw.notify('请先选择要删除的变体!', {type: 'warn'});
            return;
        }
        
        if (cardData.currentVariantIndex === 0) {
            mw.notify('不能删除主卡牌变体!', {type: 'warn'});
            return;
        }
        
        if (!confirm('确定要删除这个变体吗?')) {
            return;
        }
        
        cardData.currentCard.variants.splice(cardData.currentVariantIndex, 1);
        cardData.currentVariantIndex = 0;
        updateVariantList();
        updateCode();
        setFormData(cardData.currentCard, 0);
        mw.notify('变体删除成功!', {type: 'success'});
    }
    
    // 更新卡牌列表
    function updateCardList() {
        var list = $('#card-list').empty();
        cardData.cards.forEach(function(card, index) {
            var item = $('<div>')
                .addClass('card-list-item')
                .attr('data-index', index)
                .text(card.name)
                .click(function() {
                    onCardSelected(index);
                });
            
            if (cardData.currentCard === card) {
                item.addClass('card-list-item-selected');
            }
            
            list.append(item);
        });
    }
    
    // 更新变体列表
    function updateVariantList() {
        var list = $('#variant-list').empty();
        if (cardData.currentCard) {
            cardData.currentCard.variants.forEach(function(variant, index) {
                var deck = variant['卡组'] || '未知';
                var text = index === 0 ? '主卡牌 (' + deck + ')' : '变体 ' + index + ' (灵光一闪)';
                
                var item = $('<div>')
                    .addClass('card-list-item')
                    .text(text)
                    .click(function() {
                        onVariantSelected(index);
                    });
                
                if (cardData.currentVariantIndex === index) {
                    item.addClass('card-list-item-selected');
                }
                
                list.append(item);
            });
        }
    }
    
    // 卡牌选择事件
    function onCardSelected(index) {
        cardData.currentCard = cardData.cards[index];
        cardData.currentVariantIndex = 0;
        updateCardList();
        updateVariantList();
        setFormData(cardData.currentCard, 0);
    }
    
    // 变体选择事件
    function onVariantSelected(index) {
        if (!cardData.currentCard) return;
        cardData.currentVariantIndex = index;
        updateVariantList();
        setFormData(cardData.currentCard, index);
    }
    
    // 更新卡牌顺序
    function updateCardOrder() {
        var newCards = [];
        $('#card-list .card-list-item').each(function() {
            var index = $(this).attr('data-index');
            newCards.push(cardData.cards[index]);
        });
        cardData.cards = newCards;
        updateCardList();
        updateCode();
    }
    
    // 转义Lua字符串
    function escapeLuaString(str) {
        if (typeof str !== 'string') return str;
        return str.replace(/\\/g, '\\\\')
                  .replace(/"/g, '\\"')
                  .replace(/\n/g, '\\n');
    }
    
    // 生成Lua代码
    function generateLuaCode() {
        if (cardData.cards.length === 0) {
            return '-- 暂无数据';
        }
        
        var lua = 'local p = {}\n\n';
        
        // 生成 cardOrder(不包含衍生卡牌)
        lua += 'local cardOrder = {\n';
        cardData.cards.forEach(function(card) {
            if (card.variants[0] && card.variants[0]['卡组'] !== '衍生卡牌') {
                lua += '    "' + escapeLuaString(card.name) + '",\n';
            }
        });
        lua += '}\n\n';
        
        // 生成 card 数据
        lua += 'local card = {\n';
        
        cardData.cards.forEach(function(card) {
            lua += '    ["' + escapeLuaString(card.name) + '"] = {\n';
            
            card.variants.forEach(function(variant) {
                lua += '        {\n';
                
                // 按固定顺序输出字段
                fieldDefinitions.cardOrder.forEach(function(field) {
                    if (variant.hasOwnProperty(field) && variant[field] !== null && variant[field] !== '') {
                        var value = variant[field];
                        if (typeof value === 'string') {
                            lua += '            ["' + field + '"] = "' + escapeLuaString(value) + '",\n';
                        } else if (typeof value === 'number') {
                            lua += '            ["' + field + '"] = ' + value + ',\n';
                        }
                    }
                });
                
                lua += '        },\n';
            });
            
            lua += '    },\n';
        });
        
        lua += '}\n\n';
        lua += 'p.card = card\n';
        lua += 'p.cardOrder = cardOrder\n\n';
        lua += 'return p\n';
        
        return lua;
    }
    
    // 更新代码显示
    function updateCode() {
        var code = generateLuaCode();
        $('#code-display').val(code);
    }
    
    // 复制代码
    function copyCode() {
        var code = $('#code-display');
        code.select();
        document.execCommand('copy');
        mw.notify('代码已复制到剪贴板!', {type: 'success'});
    }
    
    // 从Wiki加载数据
    function loadFromWiki() {
        mw.notify('正在加载数据...', {type: 'info'});
        
        // 获取所有模块:卡牌/开头的页面
        new mw.Api().get({
            action: 'query',
            list: 'allpages',
            apprefix: '卡牌/',
            apnamespace: 828, // Module namespace
            aplimit: 500
        }).done(function(data) {
            if (!data.query || !data.query.allpages || data.query.allpages.length === 0) {
                mw.notify('未找到卡牌模块!', {type: 'warn'});
                return;
            }
            
            var pages = data.query.allpages;
            var loadedCards = [];
            var loadCount = 0;
            
            pages.forEach(function(page) {
                var pageName = page.title;
                
                // 加载每个模块的内容
                new mw.Api().get({
                    action: 'query',
                    prop: 'revisions',
                    titles: pageName,
                    rvprop: 'content',
                    rvslots: 'main'
                }).done(function(moduleData) {
                    loadCount++;
                    
                    var pageId = Object.keys(moduleData.query.pages)[0];
                    var content = moduleData.query.pages[pageId].revisions[0].slots.main['*'];
                    
                    // 解析Lua内容
                    var parsed = parseLuaContent(content);
                    if (parsed && parsed.length > 0) {
                        loadedCards = loadedCards.concat(parsed);
                    }
                    
                    // 所有页面加载完成
                    if (loadCount === pages.length) {
                        cardData.cards = loadedCards;
                        cardData.currentCard = null;
                        cardData.currentVariantIndex = null;
                        updateCardList();
                        updateVariantList();
                        updateCode();
                        clearForm();
                        mw.notify('成功加载 ' + loadedCards.length + ' 张卡牌!', {type: 'success'});
                    }
                });
            });
        }).fail(function() {
            mw.notify('加载失败!', {type: 'error'});
        });
    }
    
    // 解析Lua内容
    function parseLuaContent(content) {
        var cards = [];
        
        try {
            // 提取 cardOrder
            var cardOrderMatch = content.match(/local\s+cardOrder\s*=\s*\{([^}]+)\}/s);
            var cardOrder = [];
            if (cardOrderMatch) {
                var orderContent = cardOrderMatch[1];
                var nameMatches = orderContent.match(/"([^"]+)"/g);
                if (nameMatches) {
                    cardOrder = nameMatches.map(function(m) { return m.slice(1, -1); });
                }
            }
            
            // 提取 card 表
            var cardTableMatch = content.match(/local\s+card\s*=\s*\{(.+)\}\s*p\.card/s);
            if (!cardTableMatch) return cards;
            
            var cardContent = cardTableMatch[1];
            
            // 提取所有卡牌名称
            var allCardNames = [];
            var namePattern = /\["([^"]+)"\]\s*=\s*\{/g;
            var match;
            while ((match = namePattern.exec(cardContent)) !== null) {
                var name = match[1];
                if (allCardNames.indexOf(name) === -1) {
                    allCardNames.push(name);
                }
            }
            
            // 合并cardOrder和实际卡牌名称
            var finalCardNames = [];
            cardOrder.forEach(function(name) {
                if (allCardNames.indexOf(name) !== -1) {
                    finalCardNames.push(name);
                    allCardNames.splice(allCardNames.indexOf(name), 1);
                }
            });
            finalCardNames = finalCardNames.concat(allCardNames);
            
            // 解析每个卡牌
            finalCardNames.forEach(function(cardName) {
                var variants = extractCardVariants(cardContent, cardName);
                if (variants.length > 0) {
                    cards.push({
                        name: cardName,
                        variants: variants
                    });
                }
            });
            
        } catch (e) {
            console.error('解析错误:', e);
        }
        
        return cards;
    }
    
    // 提取卡牌变体
    function extractCardVariants(content, cardName) {
        var variants = [];
        var escapedName = cardName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        var pattern = new RegExp('\\["' + escapedName + '"\\]\\s*=\\s*\\{', 'g');
        var match = pattern.exec(content);
        
        if (!match) return variants;
        
        var startPos = match.index + match[0].length;
        var cardBlock = extractBalancedBraces(content, startPos);
        
        if (!cardBlock) return variants;
        
        // 解析所有变体
        var pos = 0;
        while (pos < cardBlock.length) {
            while (pos < cardBlock.length && /\s/.test(cardBlock[pos])) pos++;
            if (pos >= cardBlock.length) break;
            
            if (cardBlock[pos] === '{') {
                var variantContent = extractBalancedBraces(cardBlock, pos + 1);
                if (variantContent) {
                    var variant = parseVariant(variantContent);
                    if (Object.keys(variant).length > 0) {
                        variants.push(variant);
                    }
                    pos += variantContent.length + 2;
                } else {
                    pos++;
                }
            } else {
                pos++;
            }
        }
        
        return variants;
    }
    
    // 提取平衡的大括号内容
    function extractBalancedBraces(text, startPos) {
        var braceCount = 1;
        var pos = startPos;
        var inString = false;
        var escapeNext = false;
        var result = [];
        
        while (pos < text.length && braceCount > 0) {
            var char = text[pos];
            
            if (escapeNext) {
                result.push(char);
                escapeNext = false;
                pos++;
                continue;
            }
            
            if (char === '\\' && inString) {
                result.push(char);
                escapeNext = true;
                pos++;
                continue;
            }
            
            if (char === '"') {
                inString = !inString;
                result.push(char);
                pos++;
                continue;
            }
            
            if (!inString) {
                if (char === '{') {
                    braceCount++;
                } else if (char === '}') {
                    braceCount--;
                    if (braceCount === 0) break;
                }
            }
            
            result.push(char);
            pos++;
        }
        
        return braceCount === 0 ? result.join('') : null;
    }
    
    // 解析变体
    function parseVariant(content) {
        var variant = {};
        var pos = 0;
        
        while (pos < content.length) {
            while (pos < content.length && /[\s,]/.test(content[pos])) pos++;
            if (pos >= content.length) break;
            
            if (content[pos] === '[') {
                var fieldMatch = content.substring(pos).match(/\["([^"]+)"\]\s*=\s*/);
                if (fieldMatch) {
                    var fieldName = fieldMatch[1];
                    pos += fieldMatch[0].length;
                    
                    var result = extractFieldValue(content, pos);
                    if (result.value !== null) {
                        variant[fieldName] = result.value;
                        pos += result.length;
                    } else {
                        pos++;
                    }
                } else {
                    pos++;
                }
            } else {
                pos++;
            }
        }
        
        return variant;
    }
    
    // 提取字段值
    function extractFieldValue(text, startPos) {
        var pos = startPos;
        
        while (pos < text.length && /\s/.test(text[pos])) pos++;
        if (pos >= text.length) return {value: null, length: 0};
        
        // 字符串值
        if (text[pos] === '"') {
            pos++;
            var valueChars = [];
            var escapeNext = false;
            
            while (pos < text.length) {
                var char = text[pos];
                
                if (escapeNext) {
                    if (char === 'n') valueChars.push('\n');
                    else if (char === 't') valueChars.push('\t');
                    else if (char === '\\') valueChars.push('\\');
                    else if (char === '"') valueChars.push('"');
                    else valueChars.push(char);
                    escapeNext = false;
                    pos++;
                    continue;
                }
                
                if (char === '\\') {
                    escapeNext = true;
                    pos++;
                    continue;
                }
                
                if (char === '"') {
                    pos++;
                    break;
                }
                
                valueChars.push(char);
                pos++;
            }
            
            return {
                value: valueChars.join(''),
                length: pos - startPos
            };
        }
        // 数字或其他值
        else {
            var valueMatch = text.substring(pos).match(/([^,\n}\]]+)/);
            if (valueMatch) {
                var valueStr = valueMatch[1].trim();
                var length = valueMatch[0].length;
                
                if (/^\d+$/.test(valueStr) || /^-\d+$/.test(valueStr)) {
                    return {value: parseInt(valueStr), length: length};
                } else {
                    return {value: valueStr, length: length};
                }
            }
        }
        
        return {value: null, length: 0};
    }
    
    // 保存到Wiki
    function saveToWiki() {
        if (cardData.cards.length === 0) {
            mw.notify('没有数据可保存!', {type: 'warn'});
            return;
        }
        
        if (!confirm('确定要保存数据到Wiki吗?这将覆盖现有的模块页面!')) {
            return;
        }
        
        mw.notify('正在保存数据...', {type: 'info'});
        
        // 按角色名分组卡牌
        var groupedCards = {};
        cardData.cards.forEach(function(card) {
            // 这里需要用户手动指定角色名,简化处理,可以提示用户
            // 暂时使用第一个卡牌的art文件名推测角色
            var characterName = prompt('请为卡牌 "' + card.name + '" 指定角色名:', '');
            if (!characterName) {
                characterName = '未分类';
            }
            
            if (!groupedCards[characterName]) {
                groupedCards[characterName] = [];
            }
            groupedCards[characterName].push(card);
        });
        
        // 保存每个角色的模块
        var saveCount = 0;
        var totalModules = Object.keys(groupedCards).length;
        
        Object.keys(groupedCards).forEach(function(characterName) {
            var cards = groupedCards[characterName];
            var luaCode = generateLuaCodeForCharacter(cards);
            var pageName = '模块:卡牌/' + characterName;
            
            new mw.Api().postWithToken('csrf', {
                action: 'edit',
                title: pageName,
                text: luaCode,
                summary: '通过卡牌编辑器更新',
                contentmodel: 'Scribunto'
            }).done(function() {
                saveCount++;
                if (saveCount === totalModules) {
                    mw.notify('所有数据保存成功!', {type: 'success'});
                }
            }).fail(function() {
                mw.notify('保存 ' + pageName + ' 失败!', {type: 'error'});
            });
        });
    }
    
    // 为特定角色生成Lua代码
    function generateLuaCodeForCharacter(cards) {
        var lua = 'local p = {}\n\n';
        
        lua += 'local cardOrder = {\n';
        cards.forEach(function(card) {
            if (card.variants[0] && card.variants[0]['卡组'] !== '衍生卡牌') {
                lua += '    "' + escapeLuaString(card.name) + '",\n';
            }
        });
        lua += '}\n\n';
        
        lua += 'local card = {\n';
        cards.forEach(function(card) {
            lua += '    ["' + escapeLuaString(card.name) + '"] = {\n';
            
            card.variants.forEach(function(variant) {
                lua += '        {\n';
                
                fieldDefinitions.cardOrder.forEach(function(field) {
                    if (variant.hasOwnProperty(field) && variant[field] !== null && variant[field] !== '') {
                        var value = variant[field];
                        if (typeof value === 'string') {
                            lua += '            ["' + field + '"] = "' + escapeLuaString(value) + '",\n';
                        } else if (typeof value === 'number') {
                            lua += '            ["' + field + '"] = ' + value + ',\n';
                        }
                    }
                });
                
                lua += '        },\n';
            });
            
            lua += '    },\n';
        });
        lua += '}\n\n';
        
        lua += 'p.card = card\n';
        lua += 'p.cardOrder = cardOrder\n\n';
        lua += 'return p\n';
        
        return lua;
    }
    
    // 初始化
    $(function() {
        initUI();
    });
    
})();