MediaWiki

Card.js:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
创建页面,内容为“* * MediaWiki卡牌编辑器 * 用于管理"模块:卡牌/角色名"页面 * 放置于 MediaWiki:card.js:​ (function() { 'use strict'; // 检查是否在正确的页面加载 if (mw.config.get('wgCanonicalSpecialPageName') !== 'Blankpage' || !window.location.href.includes('卡牌管理')) { return; } var CardEditor = { cards: [], currentCard: null, currentVariantIndex: null, api: new…”
 
律Rhyme留言 | 贡献
无编辑摘要
第1行: 第1行:
/**
// MediaWiki:Card.js
* MediaWiki卡牌编辑器
* 用于管理"模块:卡牌/角色名"页面
* 放置于 MediaWiki:card.js
*/
 
(function() {
(function() {
     'use strict';
     'use strict';
 
   
     // 检查是否在正确的页面加载
     // 检查是否在正确的页面
     if (mw.config.get('wgCanonicalSpecialPageName') !== 'Blankpage' ||
     if (mw.config.get('wgPageName') !== 'MediaWiki:Card') {
        !window.location.href.includes('卡牌管理')) {
         return;
         return;
     }
     }


     var CardEditor = {
     var api = new mw.Api();
        cards: [],
    var cardData = {};
        currentCard: null,
    var currentCharacter = null;
        currentVariantIndex: null,
        api: new mw.Api(),


        // 初始化
    // 获取所有"模块:卡牌/角色名"页面
        init: function() {
    function loadAllCardModules() {
            this.createUI();
        api.get({
             this.loadAllCards();
             action: 'query',
             this.bindEvents();
             list: 'allpages',
        },
            apprefix: '卡牌/',
 
            apnamespace: 828, // Module namespace
        // 创建UI界面
            aplimit: 'max'
        createUI: function() {
        }).done(function(data) {
            var $container = $('<div>').attr('id', 'card-editor-container').css({
             var pages = data.query.allpages;
                'max-width': '1400px',
             var select = $('#character-select');
                'margin': '20px auto',
            select.empty();
                'font-family': 'Microsoft YaHei, 微软雅黑, sans-serif'
             select.append('<option value="">选择角色</option>');
            });
 
            // 添加样式
            this.addStyles();
 
             // 创建主布局
             var $mainLayout = $('<div>').addClass('card-editor-layout');
 
            // 左侧:输入区
             var $leftPanel = this.createInputArea();
              
              
             // 中间:列表区
             pages.forEach(function(page) {
            var $middlePanel = this.createListArea();
                 var characterName = page.title.replace('模块:卡牌/', '');
           
                 select.append($('<option>').val(characterName).text(characterName));
            // 右侧:代码显示区
            var $rightPanel = this.createCodeArea();
 
            $mainLayout.append($leftPanel, $middlePanel, $rightPanel);
            $container.append($mainLayout);
 
            // 清空页面内容并添加编辑器
            $('#mw-content-text').empty().append($container);
        },
 
        // 添加CSS样式
        addStyles: function() {
            var css = `
                .card-editor-layout {
                    display: flex;
                    gap: 15px;
                    margin-top: 20px;
                }
                .card-editor-panel {
                    flex: 1;
                    background: #fff;
                    border: 1px solid #ddd;
                    border-radius: 4px;
                    padding: 15px;
                }
                .card-editor-panel.left { flex: 2; }
                .card-editor-panel.middle { flex: 1; }
                .card-editor-panel.right { flex: 2; }
               
                .card-group {
                    border: 1px solid #ddd;
                    border-radius: 4px;
                    padding: 15px;
                    margin-bottom: 15px;
                    background: #fafafa;
                }
                .card-group-title {
                    font-size: 16px;
                    font-weight: bold;
                    color: #555;
                    margin-bottom: 12px;
                    padding-bottom: 8px;
                    border-bottom: 2px solid #4a90e2;
                }
                .card-field-row {
                    display: flex;
                    align-items: center;
                    margin-bottom: 10px;
                }
                .card-field-label {
                    min-width: 100px;
                    color: #555;
                    font-size: 13px;
                }
                .card-field-input {
                    flex: 1;
                }
                .card-field-input input,
                .card-field-input select,
                .card-field-input textarea {
                    width: 100%;
                    padding: 6px 10px;
                    border: 1px solid #ddd;
                    border-radius: 3px;
                    font-size: 13px;
                    font-family: Microsoft YaHei, 微软雅黑, sans-serif;
                }
                .card-field-input textarea {
                    resize: vertical;
                    min-height: 80px;
                }
                .card-button {
                    padding: 8px 16px;
                    border: none;
                    border-radius: 3px;
                    cursor: pointer;
                    font-size: 13px;
                    font-family: Microsoft YaHei, 微软雅黑, sans-serif;
                    transition: background-color 0.2s;
                }
                .card-button-primary {
                    background-color: #4a90e2;
                    color: white;
                }
                .card-button-primary:hover {
                    background-color: #357abd;
                }
                .card-button-success {
                    background-color: #5cb85c;
                    color: white;
                }
                .card-button-success:hover {
                    background-color: #4cae4c;
                }
                .card-button-danger {
                    background-color: #d9534f;
                    color: white;
                }
                .card-button-danger:hover {
                    background-color: #c9302c;
                }
                .card-button-info {
                    background-color: #2196F3;
                    color: white;
                    padding: 4px 10px;
                    font-size: 12px;
                }
                .card-button-row {
                    display: flex;
                    gap: 8px;
                    margin-top: 10px;
                }
                .card-list {
                    border: 1px solid #ddd;
                    border-radius: 3px;
                    max-height: 300px;
                    overflow-y: auto;
                }
                .card-list-item {
                    padding: 10px;
                    cursor: pointer;
                    border-bottom: 1px solid #eee;
                    transition: background-color 0.2s;
                }
                .card-list-item:hover {
                    background-color: #f5f5f5;
                }
                .card-list-item.active {
                    background-color: #e3f2fd;
                    color: #333;
                }
                .card-code-display {
                    background-color: #2b2b2b;
                    color: #a9b7c6;
                    font-family: Consolas, Monaco, monospace;
                    padding: 15px;
                    border-radius: 3px;
                    overflow: auto;
                    max-height: 600px;
                    font-size: 12px;
                    white-space: pre;
                }
                .card-format-buttons {
                    display: flex;
                    gap: 5px;
                    margin-bottom: 5px;
                }
                .loading-indicator {
                    text-align: center;
                    padding: 20px;
                    color: #666;
                 }
            `;
           
            $('<style>').text(css).appendTo('head');
        },
 
        // 创建输入区域
        createInputArea: function() {
            var $panel = $('<div>').addClass('card-editor-panel left');
            var $group = $('<div>').addClass('card-group');
            var $title = $('<div>').addClass('card-group-title').text('卡牌数据');
 
            $group.append($title);
 
            // 卡牌名称
            var $nameRow = this.createFieldRow('卡牌名称:',
                '<input type="text" id="card-name" placeholder="请输入卡牌名称...">');
            $group.append($nameRow);
 
            // 卡组类型
            var $deckRow = this.createFieldRow('卡组类型:',
                '<select id="card-deck"><option value="">请选择</option><option>起始卡牌</option><option>独特卡牌</option><option>灵光一闪</option><option>衍生卡牌</option></select>');
            $group.append($deckRow);
 
            // 图片文件
            var $artRow = this.createFieldRow('图片文件:',  
                '<input type="text" id="card-art" placeholder="例如: 角色名_卡牌名.png">');
            $group.append($artRow);
 
            // 属性
            var $attrRow = this.createFieldRow('属性:',
                 '<select id="card-attr"><option value="">请选择</option><option>热情</option><option>秩序</option><option>正义</option><option>本能</option><option>虚无</option></select>');
            $group.append($attrRow);
 
            // 稀有度
            var $rarityRow = this.createFieldRow('稀有度:',
                '<select id="card-rarity"><option value="">请选择</option><option>白</option><option>蓝</option><option>橙</option><option>彩</option></select>');
            $group.append($rarityRow);
 
            // AP
            var $apRow = this.createFieldRow('AP (行动点):',
                '<input type="text" id="card-ap" placeholder="输入AP数值或X...">');
            $group.append($apRow);
 
            // 类型
            var $typeRow = this.createFieldRow('卡牌类型:',
                '<select id="card-type"><option value="">请选择</option><option>攻击</option><option>技能</option><option>强化</option><option>状态异常</option></select>');
            $group.append($typeRow);
 
            // 机制
            var $mechanismRow = this.createFieldRow('卡牌机制:',
                '<input type="text" id="card-mechanism" placeholder="请输入卡牌机制...">');
            $group.append($mechanismRow);
 
            // 描述标签和格式按钮
            var $descLabel = $('<div>').addClass('card-field-row');
            $descLabel.append($('<div>').addClass('card-field-label').text('卡牌描述:'));
            var $formatBtns = $('<div>').addClass('card-format-buttons');
            $formatBtns.append(
                $('<button>').addClass('card-button card-button-info').text('蓝色文本')
                    .click(function() { CardEditor.insertTextFormat('蓝'); }),
                $('<button>').addClass('card-button card-button-info').css('background-color', '#4CAF50')
                    .text('绿色文本').click(function() { CardEditor.insertTextFormat('绿'); }),
                $('<button>').addClass('card-button card-button-info').css('background-color', '#66BB6A')
                    .text('绿色描边').click(function() { CardEditor.insertStrokeFormat(); })
            );
            $descLabel.append($formatBtns);
            $group.append($descLabel);
 
            // 描述输入框
            var $descRow = $('<div>').addClass('card-field-row');
            $descRow.append($('<div>').addClass('card-field-input')
                .html('<textarea id="card-desc" placeholder="请输入卡牌描述..."></textarea>'));
            $group.append($descRow);
 
            // 衍生卡牌
            var $derivedRow = this.createFieldRow('衍生卡牌:',
                '<input type="text" id="card-derived" placeholder="请输入衍生卡牌...">');
            $group.append($derivedRow);
 
            $panel.append($group);
 
            // 按钮组
            var $btnRow1 = $('<div>').addClass('card-button-row');
            $btnRow1.append(
                $('<button>').addClass('card-button card-button-success').text('添加卡牌')
                    .click(function() { CardEditor.addCard(); }),
                $('<button>').addClass('card-button card-button-success').text('添加变体')
                    .click(function() { CardEditor.addVariant(); })
            );
            $panel.append($btnRow1);
 
            var $btnRow2 = $('<div>').addClass('card-button-row');
            $btnRow2.append(
                $('<button>').addClass('card-button card-button-primary').text('保存数据')
                    .click(function() { CardEditor.saveData(); }),
                $('<button>').addClass('card-button card-button-primary').text('清空表单')
                    .click(function() { CardEditor.clearForm(); })
            );
            $panel.append($btnRow2);
 
            var $btnRow3 = $('<div>').addClass('card-button-row');
            $btnRow3.append(
                $('<button>').addClass('card-button card-button-primary').text('保存到Wiki')
                    .click(function() { CardEditor.saveToWiki(); })
            );
            $panel.append($btnRow3);
 
            return $panel;
        },
 
        // 创建列表区域
        createListArea: function() {
            var $panel = $('<div>').addClass('card-editor-panel middle');
 
            // 卡牌列表
            var $cardGroup = $('<div>').addClass('card-group');
            $cardGroup.append($('<div>').addClass('card-group-title').text('卡牌列表'));
            $cardGroup.append($('<div>').addClass('card-list').attr('id', 'card-list'));
            $panel.append($cardGroup);
 
            // 变体列表
            var $variantGroup = $('<div>').addClass('card-group');
            $variantGroup.append($('<div>').addClass('card-group-title').text('变体列表'));
            $variantGroup.append($('<div>').addClass('card-list').attr('id', 'variant-list'));
            $panel.append($variantGroup);
 
            // 删除按钮
            var $btnRow = $('<div>').addClass('card-button-row');
            $btnRow.append(
                $('<button>').addClass('card-button card-button-danger').text('删除卡牌')
                    .click(function() { CardEditor.deleteCard(); }),
                $('<button>').addClass('card-button card-button-danger').text('删除变体')
                    .click(function() { CardEditor.deleteVariant(); })
            );
            $panel.append($btnRow);
 
            return $panel;
        },
 
        // 创建代码显示区域
        createCodeArea: function() {
            var $panel = $('<div>').addClass('card-editor-panel right');
           
            var $group = $('<div>').addClass('card-group');
            $group.append($('<div>').addClass('card-group-title').text('Lua代码预览'));
            $group.append($('<div>').addClass('card-code-display').attr('id', 'code-display')
                .text('-- 暂无数据'));
            $panel.append($group);
 
            // 按钮
            var $btnRow = $('<div>').addClass('card-button-row');
            $btnRow.append(
                $('<button>').addClass('card-button card-button-primary').text('复制代码')
                    .click(function() { CardEditor.copyCode(); }),
                $('<button>').addClass('card-button card-button-primary').text('刷新列表')
                    .click(function() { CardEditor.loadAllCards(); })
            );
            $panel.append($btnRow);
 
            return $panel;
        },
 
        // 创建字段行
        createFieldRow: function(label, inputHtml) {
            var $row = $('<div>').addClass('card-field-row');
            $row.append($('<div>').addClass('card-field-label').text(label));
            $row.append($('<div>').addClass('card-field-input').html(inputHtml));
            return $row;
        },
 
        // 绑定事件
        bindEvents: function() {
            var self = this;
           
            // 卡牌列表点击
            $('#card-list').on('click', '.card-list-item', function() {
                var index = $(this).data('index');
                self.onCardSelected(index);
             });
             });
        });
    }


            // 变体列表点击
    // 加载指定角色的卡牌数据
            $('#variant-list').on('click', '.card-list-item', function() {
    function loadCharacterCards(characterName) {
                var index = $(this).data('index');
        api.get({
                self.onVariantSelected(index);
             action: 'query',
             });
             prop: 'revisions',
        },
             titles: '模块:卡牌/' + characterName,
 
             rvprop: 'content',
        // 插入文本格式
             rvslots: 'main'
        insertTextFormat: function(color) {
        }).done(function(data) {
            var $desc = $('#card-desc');
             var pages = data.query.pages;
            var text = $desc.val();
             for (var pageId in pages) {
            var start = $desc[0].selectionStart;
                if (pages[pageId].revisions) {
            var end = $desc[0].selectionEnd;
                    var content = pages[pageId].revisions[0].slots.main['*'];
            var selectedText = text.substring(start, end);
                     parseModuleContent(content, characterName);
           
             var formatted = selectedText ?
                `{{文本|${color}|${selectedText}}}` :  
                `{{文本|${color}|}}`;
           
            var newText = text.substring(0, start) + formatted + text.substring(end);
            $desc.val(newText);
           
             // 设置光标位置
            var newPos = start + formatted.length - (selectedText ? 0 : 2);
            $desc[0].selectionStart = $desc[0].selectionEnd = newPos;
             $desc.focus();
        },
 
        // 插入描边格式
        insertStrokeFormat: function() {
            var $desc = $('#card-desc');
            var text = $desc.val();
            var start = $desc[0].selectionStart;
            var end = $desc[0].selectionEnd;
            var selectedText = text.substring(start, end);
           
             var formatted = selectedText ?
                `{{描边|绿|${selectedText}}}` :  
                `{{描边|绿|}}`;
           
            var newText = text.substring(0, start) + formatted + text.substring(end);
            $desc.val(newText);
           
            var newPos = start + formatted.length - (selectedText ? 0 : 2);
            $desc[0].selectionStart = $desc[0].selectionEnd = newPos;
            $desc.focus();
        },
 
        // 获取表单数据
        getCardData: function() {
             var variant = {};
 
            var art = $('#card-art').val().trim();
             if (art) variant.art = art;
 
            var deck = $('#card-deck').val().trim();
            if (deck) variant['卡组'] = deck;
 
            var attr = $('#card-attr').val().trim();
            if (attr) variant['属性'] = attr;
 
            var rarity = $('#card-rarity').val().trim();
            if (rarity) variant['稀有度'] = rarity;
 
            var ap = $('#card-ap').val().trim();
            if (ap) {
                if (ap.toUpperCase() === 'X') {
                     variant.AP = 'X';
                } else if (/^\d+$/.test(ap)) {
                    variant.AP = parseInt(ap);
                } else {
                    variant.AP = ap;
                 }
                 }
             }
             }
        });
    }


            var mechanism = $('#card-mechanism').val().trim();
    // 解析模块内容
            if (mechanism) variant['机制'] = mechanism;
    function parseModuleContent(content, characterName) {
 
        try {
             var type = $('#card-type').val().trim();
             // 提取card表和cardOrder数组
            if (type) variant['类型'] = type;
             var cardMatch = content.match(/local\s+card\s*=\s*\{[\s\S]*?\n\}/);
 
             var orderMatch = content.match(/local\s+cardOrder\s*=\s*\{[\s\S]*?\n\}/);
             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: Object.keys(variant).length > 0 ? [variant] : [{}]
            };
        },
 
        // 设置表单数据
        setCardData: function(card, variantIndex) {
            variantIndex = variantIndex || 0;
              
              
            $('#card-name').val(card.name);
             if (cardMatch && orderMatch) {
 
                 // 转换Lua表格式为JavaScript对象
             if (variantIndex < card.variants.length) {
                 var cardDataStr = cardMatch[0]
                 var variant = card.variants[variantIndex];
                    .replace(/local\s+card\s*=/, 'var cardData =')
                 var isVariant = variant['卡组'] === '灵光一闪';
                    .replace(/\["([^"]+)"\]/g, '"$1"')
 
                    .replace(/\[(\d+)\]/g, '$1')
                // 设置字段是否可编辑
                    .replace(/nil/g, 'null');
                $('#card-name').prop('disabled', isVariant);
                   
                $('#card-art').prop('disabled', isVariant);
                 var orderDataStr = orderMatch[0]
                $('#card-attr').prop('disabled', isVariant);
                    .replace(/local\s+cardOrder\s*=/, 'var cardOrder =')
                $('#card-rarity').prop('disabled', isVariant);
                    .replace(/"/g, '"');
                $('#card-derived').prop('disabled', isVariant);
                  
 
                 eval(cardDataStr);
                // 设置值
                 eval(orderDataStr);
                $('#card-art').val(variant.art || '');
                  
                 $('#card-deck').val(variant['卡组'] || '');
                 currentCharacter = characterName;
                $('#card-attr').val(variant['属性'] || '');
                 displayCards(cardData, cardOrder);
                 $('#card-rarity').val(variant['稀有度'] || '');
                 $('#card-ap').val(variant.AP !== undefined ? variant.AP : '');
                 $('#card-mechanism').val(variant['机制'] || '');
                 $('#card-type').val(variant['类型'] || '');
                 $('#card-desc').val(variant['描述'] || '');
                 $('#card-derived').val(variant['衍生卡牌'] || '');
             }
             }
         },
         } catch (e) {
            console.error('解析失败:', e);
            mw.notify('解析模块内容失败', { type: 'error' });
        }
    }


        // 清空表单
    // 显示卡牌列表
        clearForm: function() {
    function displayCards(cards, order) {
            $('#card-name, #card-art, #card-ap, #card-mechanism, #card-desc, #card-derived').val('');
        var container = $('#cards-container');
            $('#card-deck, #card-attr, #card-rarity, #card-type').val('');
        container.empty();
            $('#card-name, #card-art, #card-attr, #card-rarity, #card-derived').prop('disabled', false);
          
            this.currentCard = null;
         // 按照顺序显示卡牌
            this.currentVariantIndex = null;
         (order || Object.keys(cards)).forEach(function(cardName) {
         },
             if (cards[cardName]) {
 
                 var cardDiv = createCardElement(cardName, cards[cardName]);
         // 添加卡牌
                 container.append(cardDiv);
         addCard: function() {
            var cardData = this.getCardData();
             if (!cardData.name) {
                 mw.notify('卡牌名称不能为空!', { type: 'error' });
                 return;
             }
             }
        });
    }


            this.cards.push(cardData);
    // 创建卡牌元素
            this.currentCard = cardData;
    function createCardElement(cardName, variants) {
            this.currentVariantIndex = 0;
        var cardDiv = $('<div>').addClass('card-item');
            this.updateCardList();
         var header = $('<h3>').text(cardName).click(function() {
            this.updateVariantList();
             $(this).next('.card-variants').toggle();
            this.updateCode();
        });
            this.clearForm();
        cardDiv.append(header);
            mw.notify('卡牌"' + cardData.name + '"添加成功!', { type: 'success' });
          
        },
         var variantsDiv = $('<div>').addClass('card-variants');
 
        variants.forEach(function(variant, index) {
        // 添加变体
             var variantDiv = createVariantElement(cardName, variant, index);
        addVariant: function() {
             variantsDiv.append(variantDiv);
            if (!this.currentCard) {
        });
                mw.notify('请先选择一个卡牌!', { type: 'error' });
          
                return;
         // 添加新变体按钮
            }
         var addButton = $('<button>').text('添加变体').click(function() {
 
             addCardVariant(cardName);
            var variantData = this.getCardData();
        });
            var variant = variantData.variants[0];
        variantsDiv.append(addButton);
            variant['卡组'] = '灵光一闪';
       
 
        cardDiv.append(variantsDiv);
            this.currentCard.variants.push(variant);
        return cardDiv;
            this.currentVariantIndex = this.currentCard.variants.length - 1;
    }
            this.updateVariantList();
            this.updateCode();
            mw.notify('为"' + this.currentCard.name + '"添加变体成功!', { type: 'success' });
         },
 
        // 保存数据
        saveData: function() {
            if (!this.currentCard || this.currentVariantIndex === null) {
                mw.notify('请先选择要保存的卡牌或变体!', { type: 'error' });
                return;
            }
 
            var cardData = this.getCardData();
            var isVariant = this.currentVariantIndex > 0;
 
            if (isVariant) {
                var 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();
            this.updateVariantList();
            this.updateCode();
            mw.notify('数据保存成功!', { type: 'success' });
        },
 
        // 删除卡牌
        deleteCard: function() {
             if (!this.currentCard) {
                mw.notify('请先选择要删除的卡牌!', { type: 'error' });
                return;
            }
 
            if (!confirm('确定要删除卡牌"' + this.currentCard.name + '"吗?')) {
                return;
            }
 
            var index = this.cards.indexOf(this.currentCard);
            if (index > -1) {
                this.cards.splice(index, 1);
            }
 
            this.currentCard = null;
            this.currentVariantIndex = null;
            this.updateCardList();
            this.updateVariantList();
            this.updateCode();
            this.clearForm();
            mw.notify('卡牌删除成功!', { type: 'success' });
         },
 
         // 删除变体
        deleteVariant: function() {
            if (!this.currentCard || this.currentVariantIndex === null) {
                mw.notify('请先选择要删除的变体!', { type: 'error' });
                return;
            }
 
            if (this.currentVariantIndex === 0) {
                mw.notify('不能删除主卡牌变体!', { type: 'error' });
                return;
            }
 
            if (!confirm('确定要删除这个变体吗?')) {
                return;
            }
 
            this.currentCard.variants.splice(this.currentVariantIndex, 1);
             this.currentVariantIndex = 0;
            this.updateVariantList();
             this.updateCode();
            this.setCardData(this.currentCard, 0);
            mw.notify('变体删除成功!', { type: 'success' });
         },
 
         // 选择卡牌
         onCardSelected: function(index) {
            this.currentCard = this.cards[index];
            this.currentVariantIndex = 0;
            this.updateVariantList();
            this.setCardData(this.currentCard, 0);
           
            $('#card-list .card-list-item').removeClass('active');
            $('#card-list .card-list-item').eq(index).addClass('active');
        },
 
        // 选择变体
        onVariantSelected: function(index) {
             if (!this.currentCard) return;
           
            this.currentVariantIndex = index;
            this.setCardData(this.currentCard, index);
           
            $('#variant-list .card-list-item').removeClass('active');
            $('#variant-list .card-list-item').eq(index).addClass('active');
        },


        // 更新卡牌列表
    // 创建变体元素
         updateCardList: function() {
    function createVariantElement(cardName, variant, index) {
             var $list = $('#card-list').empty();
        var variantDiv = $('<div>').addClass('card-variant');
       
         var fields = [
            { key: 'art', label: '图片', type: 'text' },
            { key: '卡组', label: '卡组', type: 'select',
              options: ['起始卡牌', '独特卡牌', '衍生卡牌', '灵光一闪', '神光一闪'] },
            { key: '属性', label: '属性', type: 'select',
              options: ['热情', '秩序', '正义', '本能', '虚无'] },
            { key: '稀有度', label: '稀有度', type: 'select',
              options: ['白', '蓝', '橙', '彩'] },
            { key: 'AP', label: 'AP', type: 'number' },
            { key: '类型', label: '类型', type: 'select',
              options: ['攻击', '技能', '强化', '状态异常'] },
            { key: '机制', label: '机制', type: 'text' },
            { key: '描述', label: '描述', type: 'textarea' },
            { key: '衍生卡牌', label: '衍生卡牌', type: 'text' }
        ];
       
        fields.forEach(function(field) {
             var fieldDiv = $('<div>').addClass('field');
            var label = $('<label>').text(field.label + ': ');
            var input;
              
              
             this.cards.forEach(function(card, index) {
             if (field.type === 'select') {
                 var $item = $('<div>').addClass('card-list-item')
                 input = $('<select>');
                    .text(card.name)
                $('<option>').val('').text('--选择--').appendTo(input);
                    .data('index', index);
                 field.options.forEach(function(opt) {
                $list.append($item);
                     $('<option>').val(opt).text(opt).appendTo(input);
            });
        },
 
        // 更新变体列表
        updateVariantList: function() {
            var $list = $('#variant-list').empty();
           
            if (this.currentCard) {
                 this.currentCard.variants.forEach(function(variant, index) {
                     var deck = variant['卡组'] || '未知';
                    var label = index === 0 ?
                        '主卡牌 (' + deck + ')' :
                        '变体 ' + index + ' (灵光一闪)';
                   
                    var $item = $('<div>').addClass('card-list-item')
                        .text(label)
                        .data('index', index);
                    $list.append($item);
                 });
                 });
                input.val(variant[field.key] || '');
            } else if (field.type === 'textarea') {
                input = $('<textarea>').val(variant[field.key] || '');
            } else {
                input = $('<input>').attr('type', field.type).val(variant[field.key] || '');
             }
             }
        },
        // 生成Lua代码
        generateLuaCode: function() {
            if (this.cards.length === 0) {
                return '-- 暂无数据';
            }
            var lua = 'local p = {}\n\n';
            // cardOrder
            lua += 'local cardOrder = {\n';
            this.cards.forEach(function(card) {
                lua += '    "' + CardEditor.escapeLuaString(card.name) + '",\n';
            });
            lua += '}\n';
            // card数据
            lua += 'local card = {\n';
            this.cards.forEach(function(card) {
                lua += '    ["' + CardEditor.escapeLuaString(card.name) + '"] = {\n';
               
                card.variants.forEach(function(variant) {
                    lua += '        {\n';
                   
                    var fieldOrder = ['art', '卡组', '属性', '稀有度', 'AP', '机制', '类型', '描述', '衍生卡牌'];
                    fieldOrder.forEach(function(field) {
                        if (variant[field] !== undefined && variant[field] !== '') {
                            var value = variant[field];
                            if (typeof value === 'string') {
                                lua += '            ["' + field + '"] = "' +
                                    CardEditor.escapeLuaString(value) + '",\n';
                            } else {
                                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;
        },
        // 转义Lua字符串
        escapeLuaString: function(str) {
            if (typeof str !== 'string') return str;
            return str.replace(/\\/g, '\\\\')
                      .replace(/"/g, '\\"')
                      .replace(/\n/g, '\\n');
        },
        // 更新代码显示
        updateCode: function() {
            var code = this.generateLuaCode();
            $('#code-display').text(code);
        },
        // 复制代码
        copyCode: function() {
            var code = $('#code-display').text();
            var $temp = $('<textarea>').val(code).appendTo('body').select();
            document.execCommand('copy');
            $temp.remove();
            mw.notify('代码已复制到剪贴板!', { type: 'success' });
        },
        // 从Wiki加载所有卡牌
        loadAllCards: function() {
            var self = this;
            $('#code-display').html('<div class="loading-indicator">正在加载卡牌数据...</div>');
              
              
             // 获取所有"模块:卡牌/"开头的页面
             input.attr('data-card', cardName)
            this.api.get({
                .attr('data-index', index)
                action: 'query',
                .attr('data-field', field.key);
                list: 'allpages',
                apprefix: '卡牌/',
                apnamespace: 828, // 模块命名空间
                aplimit: 500
            }).done(function(data) {
                if (data.query && data.query.allpages) {
                    var pages = data.query.allpages;
                    self.loadCardsFromPages(pages);
                } else {
                    mw.notify('未找到卡牌页面', { type: 'warn' });
                    self.updateCode();
                }
            }).fail(function() {
                mw.notify('加载卡牌列表失败', { type: 'error' });
                self.updateCode();
            });
        },
 
        // 从页面列表加载卡牌
        loadCardsFromPages: function(pages) {
            var self = this;
            var promises = [];
              
              
             pages.forEach(function(page) {
             fieldDiv.append(label).append(input);
                var pageName = page.title;
            variantDiv.append(fieldDiv);
                var promise = self.api.get({
        });
                    action: 'query',
       
                    prop: 'revisions',
        // 删除按钮
                    titles: pageName,
        var deleteButton = $('<button>').text('删除').click(function() {
                    rvprop: 'content',
            deleteCardVariant(cardName, index);
                    rvslots: 'main'
        });
                });
        variantDiv.append(deleteButton);
                promises.push(promise);
       
            });
        return variantDiv;
    }


            Promise.all(promises).then(function(results) {
    // 添加新卡牌
                self.cards = [];
    function addNewCard() {
               
        var cardName = prompt('输入新卡牌名称:');
                results.forEach(function(data) {
        if (!cardName) return;
                    if (data.query && data.query.pages) {
       
                        var pageId = Object.keys(data.query.pages)[0];
        cardData[cardName] = [{
                        var page = data.query.pages[pageId];
            art: '',
                       
            '卡组': '',
                        if (page.revisions && page.revisions[0]) {
            '属性': '',
                            var content = page.revisions[0].slots.main['*'];
            '稀有度': '',
                            var parsedCards = self.parseLuaContent(content);
            'AP': 1,
                           
            '类型': '',
                            if (parsedCards.length > 0) {
            '机制': '',
                                self.cards = self.cards.concat(parsedCards);
            '描述': '',
                            }
            '衍生卡牌': ''
                        }
        }];
                    }
       
                });
        displayCards(cardData, Object.keys(cardData));
    }


                self.updateCardList();
    // 添加卡牌变体
                self.updateCode();
    function addCardVariant(cardName) {
                mw.notify('成功加载 ' + self.cards.length + ' 张卡牌', { type: 'success' });
        if (!cardData[cardName]) {
             }).catch(function() {
            cardData[cardName] = [];
                mw.notify('加载卡牌数据失败', { type: 'error' });
        }
                self.updateCode();
       
            });
        cardData[cardName].push({
        },
            art: '',
            '卡组': '',
            '属性': '',
            '稀有度': '',
            'AP': 1,
            '类型': '',
             '机制': '',
            '描述': '',
            '衍生卡牌': ''
        });
       
        displayCards(cardData, Object.keys(cardData));
    }


        // 解析Lua内容
    // 删除卡牌变体
        parseLuaContent: function(content) {
    function deleteCardVariant(cardName, index) {
            var cards = [];
        if (confirm('确认删除这个变体?')) {
           
            cardData[cardName].splice(index, 1);
            try {
            if (cardData[cardName].length === 0) {
                // 提取cardOrder
                 delete cardData[cardName];
                var cardOrderMatch = content.match(/local\s+cardOrder\s*=\s*\{([^}]+)\}/);
                var cardOrder = [];
                if (cardOrderMatch) {
                    var matches = cardOrderMatch[1].match(/"([^"]+)"/g);
                    if (matches) {
                        cardOrder = matches.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 = this.extractAllCardNames(cardContent);
 
                // 合并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);
 
                // 按顺序处理每个卡牌
                var self = this;
                finalCardNames.forEach(function(cardName) {
                    var variants = self.extractCardVariants(cardContent, cardName);
                    if (variants.length > 0) {
                        cards.push({
                            name: cardName,
                            variants: variants
                        });
                    }
                });
 
            } catch (e) {
                console.error('解析Lua内容失败:', e);
             }
             }
            displayCards(cardData, Object.keys(cardData));
        }
    }


            return cards;
    // 保存数据
        },
    function saveCardData() {
 
        if (!currentCharacter) {
        // 提取所有卡牌名称
             mw.notify('请先选择角色', { type: 'warning' });
        extractAllCardNames: function(cardContent) {
             return;
            var cardNames = [];
         }
            var pattern = /\["([^"]+)"\]\s*=\s*\{/g;
       
            var match;
         // 收集表单数据更新cardData
              
         $('#cards-container input, #cards-container select, #cards-container textarea').each(function() {
            while ((match = pattern.exec(cardContent)) !== null) {
             var $this = $(this);
                var name = match[1];
             var cardName = $this.data('card');
                if (cardNames.indexOf(name) === -1) {
             var index = $this.data('index');
                    cardNames.push(name);
             var field = $this.data('field');
                }
             var value = $this.val();
            }
           
             return cardNames;
         },
 
         // 提取卡牌变体
         extractCardVariants: function(cardContent, cardName) {
             var variants = [];
           
            // 转义特殊字符
             var escapedName = cardName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
             var pattern = new RegExp('\\["' + escapedName + '"\\]\\s*=\\s*\\{');
             var match = pattern.exec(cardContent);
           
            if (!match) return variants;
 
            // 提取卡牌块
            var startPos = match.index + match[0].length;
             var cardBlock = this.extractBalancedBraces(cardContent, startPos);
              
              
             if (!cardBlock) return variants;
             if (cardData[cardName] && cardData[cardName][index]) {
 
                 if (field === 'AP') {
            // 解析所有变体
                     value = parseInt(value) || 0;
            var pos = 0;
            while (pos < cardBlock.length) {
                 // 跳过空白
                while (pos < cardBlock.length && /\s/.test(cardBlock[pos])) {
                     pos++;
                 }
                 }
               
                 if (value) {
                 if (pos >= cardBlock.length) break;
                    cardData[cardName][index][field] = value;
 
                if (cardBlock[pos] === '{') {
                    var variantContent = this.extractBalancedBraces(cardBlock, pos + 1);
                    if (variantContent !== null) {
                        var variant = this.parseVariant(variantContent);
                        if (variant && Object.keys(variant).length > 0) {
                            variants.push(variant);
                        }
                        pos += variantContent.length + 2;
                    } else {
                        pos++;
                    }
                 } else {
                 } else {
                     pos++;
                     delete cardData[cardName][index][field];
                 }
                 }
             }
             }
        });
       
        var moduleContent = generateModuleContent(cardData);
       
        api.postWithToken('csrf', {
            action: 'edit',
            title: '模块:卡牌/' + currentCharacter,
            text: moduleContent,
            summary: '通过卡牌管理器更新'
        }).done(function() {
            mw.notify('保存成功!', { type: 'success' });
        }).fail(function(code, data) {
            mw.notify('保存失败: ' + (data.error ? data.error.info : code), { type: 'error' });
        });
    }


            return variants;
    // 生成模块内容
        },
    function generateModuleContent(data) {
 
        var content = 'local p = {}\n\n';
        // 提取平衡的大括号内容
       
        extractBalancedBraces: function(text, startPos) {
        // 生成cardOrder
            var braceCount = 1;
        content += 'local cardOrder = {\n';
            var pos = startPos;
        Object.keys(data).forEach(function(cardName) {
            var inString = false;
            content += '   "' + cardName + '",\n';
            var escapeNext = false;
        });
            var result = [];
        content += '}\n\n';
 
          
            while (pos < text.length && braceCount > 0) {
         // 生成card表
                var char = text[pos];
        content += 'local card = {\n';
 
         Object.keys(data).forEach(function(cardName) {
                if (escapeNext) {
             content += '    ["' + cardName + '"] = {\n';
                    result.push(char);
              
                    escapeNext = false;
             data[cardName].forEach(function(variant) {
                    pos++;
                content += '        {\n';
                    continue;
                 Object.keys(variant).forEach(function(key) {
                }
                     var value = variant[key];
 
                     if (value !== null && value !== undefined && value !== '') {
                if (char === '\\' && inString) {
                         if (key === 'AP' || !isNaN(value)) {
                    result.push(char);
                             content += '            ["' + key + '"] = ' + value + ',\n';
                    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++;
            }
 
            if (braceCount !== 0) return null;
            return result.join('');
         },
 
         // 解析变体
         parseVariant: function(variantContent) {
             var variant = {};
             var pos = 0;
 
             while (pos < variantContent.length) {
                // 跳过空白和逗号
                while (pos < variantContent.length && /[\s,]/.test(variantContent[pos])) {
                    pos++;
                 }
 
                if (pos >= variantContent.length) break;
 
                // 查找字段定义
                if (variantContent[pos] === '[') {
                     var fieldMatch = variantContent.substring(pos).match(/\["([^"]+)"\]\s*=\s*/);
                     if (fieldMatch) {
                        var fieldName = fieldMatch[1];
                        pos += fieldMatch[0].length;
 
                        var result = this.extractFieldValue(variantContent, pos);
                         if (result.value !== null) {
                             variant[fieldName] = result.value;
                            pos += result.length;
                         } else {
                         } else {
                             pos++;
                             content += '            ["' + key + '"] = "' + value.replace(/"/g, '\\"') + '",\n';
                         }
                         }
                    } else {
                        pos++;
                     }
                     }
                 } else {
                 });
                    pos++;
                 content += '       },\n';
                }
            }
 
            return variant;
        },
 
        // 提取字段值
        extractFieldValue: function(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++;
                }
 
                var value = valueChars.join('');
                var length = pos - startPos;
                return { value: value, length: length };
            }
            // 数字或其他值
            else {
                var valueMatch = text.substring(pos).match(/([^,\n}\]]+)/);
                if (valueMatch) {
                    var valueStr = valueMatch[1].trim();
                    var length = valueMatch[0].length;
 
                    if (/^-?\d+$/.test(valueStr)) {
                        return { value: parseInt(valueStr), length: length };
                    } else {
                        return { value: valueStr, length: length };
                    }
                }
            }
 
            return { value: null, length: 0 };
        },
 
        // 保存到Wiki
        saveToWiki: function() {
            if (this.cards.length === 0) {
                mw.notify('没有数据可保存!', { type: 'error' });
                return;
            }
 
            var characterName = prompt('请输入角色名称(将创建"模块:卡牌/角色名"页面):');
            if (!characterName) return;
 
            var pageName = '模块:卡牌/' + characterName;
            var content = this.generateLuaCode();
 
            var self = this;
            this.api.postWithToken('csrf', {
                action: 'edit',
                title: pageName,
                text: content,
                summary: '通过卡牌编辑器更新',
                contentformat: 'text/x-lua',
                contentmodel: 'Scribunto'
            }).done(function() {
                mw.notify('成功保存到页面: ' + pageName, { type: 'success' });
            }).fail(function(code, result) {
                mw.notify('保存失败: ' + (result.error ? result.error.info : '未知错误'), { type: 'error' });
             });
             });
         }
           
     };
            content += '    },\n';
         });
        content += '}\n\n';
       
        content += 'p.card = card\n';
        content += 'p.cardOrder = cardOrder\n\n';
        content += 'return p\n';
       
        return content;
     }


     // 在页面加载完成后初始化
     // 初始化页面
     $(function() {
     $(function() {
         CardEditor.init();
         loadAllCardModules();
       
        // 绑定事件
        $('#character-select').on('change', function() {
            var characterName = $(this).val();
            if (characterName) {
                loadCharacterCards(characterName);
            }
        });
       
        $('#add-card-btn').click(addNewCard);
        $('#save-btn').click(saveCardData);
        $('#refresh-btn').click(loadAllCardModules);
     });
     });


})();
})();

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

// MediaWiki:Card.js
(function() {
    'use strict';
    
    // 检查是否在正确的页面
    if (mw.config.get('wgPageName') !== 'MediaWiki:Card') {
        return;
    }

    var api = new mw.Api();
    var cardData = {};
    var currentCharacter = null;

    // 获取所有"模块:卡牌/角色名"页面
    function loadAllCardModules() {
        api.get({
            action: 'query',
            list: 'allpages',
            apprefix: '卡牌/',
            apnamespace: 828, // Module namespace
            aplimit: 'max'
        }).done(function(data) {
            var pages = data.query.allpages;
            var select = $('#character-select');
            select.empty();
            select.append('<option value="">选择角色</option>');
            
            pages.forEach(function(page) {
                var characterName = page.title.replace('模块:卡牌/', '');
                select.append($('<option>').val(characterName).text(characterName));
            });
        });
    }

    // 加载指定角色的卡牌数据
    function loadCharacterCards(characterName) {
        api.get({
            action: 'query',
            prop: 'revisions',
            titles: '模块:卡牌/' + characterName,
            rvprop: 'content',
            rvslots: 'main'
        }).done(function(data) {
            var pages = data.query.pages;
            for (var pageId in pages) {
                if (pages[pageId].revisions) {
                    var content = pages[pageId].revisions[0].slots.main['*'];
                    parseModuleContent(content, characterName);
                }
            }
        });
    }

    // 解析模块内容
    function parseModuleContent(content, characterName) {
        try {
            // 提取card表和cardOrder数组
            var cardMatch = content.match(/local\s+card\s*=\s*\{[\s\S]*?\n\}/);
            var orderMatch = content.match(/local\s+cardOrder\s*=\s*\{[\s\S]*?\n\}/);
            
            if (cardMatch && orderMatch) {
                // 转换Lua表格式为JavaScript对象
                var cardDataStr = cardMatch[0]
                    .replace(/local\s+card\s*=/, 'var cardData =')
                    .replace(/\["([^"]+)"\]/g, '"$1"')
                    .replace(/\[(\d+)\]/g, '$1')
                    .replace(/nil/g, 'null');
                    
                var orderDataStr = orderMatch[0]
                    .replace(/local\s+cardOrder\s*=/, 'var cardOrder =')
                    .replace(/"/g, '"');
                
                eval(cardDataStr);
                eval(orderDataStr);
                
                currentCharacter = characterName;
                displayCards(cardData, cardOrder);
            }
        } catch (e) {
            console.error('解析失败:', e);
            mw.notify('解析模块内容失败', { type: 'error' });
        }
    }

    // 显示卡牌列表
    function displayCards(cards, order) {
        var container = $('#cards-container');
        container.empty();
        
        // 按照顺序显示卡牌
        (order || Object.keys(cards)).forEach(function(cardName) {
            if (cards[cardName]) {
                var cardDiv = createCardElement(cardName, cards[cardName]);
                container.append(cardDiv);
            }
        });
    }

    // 创建卡牌元素
    function createCardElement(cardName, variants) {
        var cardDiv = $('<div>').addClass('card-item');
        var header = $('<h3>').text(cardName).click(function() {
            $(this).next('.card-variants').toggle();
        });
        cardDiv.append(header);
        
        var variantsDiv = $('<div>').addClass('card-variants');
        variants.forEach(function(variant, index) {
            var variantDiv = createVariantElement(cardName, variant, index);
            variantsDiv.append(variantDiv);
        });
        
        // 添加新变体按钮
        var addButton = $('<button>').text('添加变体').click(function() {
            addCardVariant(cardName);
        });
        variantsDiv.append(addButton);
        
        cardDiv.append(variantsDiv);
        return cardDiv;
    }

    // 创建变体元素
    function createVariantElement(cardName, variant, index) {
        var variantDiv = $('<div>').addClass('card-variant');
        
        var fields = [
            { key: 'art', label: '图片', type: 'text' },
            { key: '卡组', label: '卡组', type: 'select', 
              options: ['起始卡牌', '独特卡牌', '衍生卡牌', '灵光一闪', '神光一闪'] },
            { key: '属性', label: '属性', type: 'select', 
              options: ['热情', '秩序', '正义', '本能', '虚无'] },
            { key: '稀有度', label: '稀有度', type: 'select', 
              options: ['白', '蓝', '橙', '彩'] },
            { key: 'AP', label: 'AP', type: 'number' },
            { key: '类型', label: '类型', type: 'select', 
              options: ['攻击', '技能', '强化', '状态异常'] },
            { key: '机制', label: '机制', type: 'text' },
            { key: '描述', label: '描述', type: 'textarea' },
            { key: '衍生卡牌', label: '衍生卡牌', type: 'text' }
        ];
        
        fields.forEach(function(field) {
            var fieldDiv = $('<div>').addClass('field');
            var label = $('<label>').text(field.label + ': ');
            var input;
            
            if (field.type === 'select') {
                input = $('<select>');
                $('<option>').val('').text('--选择--').appendTo(input);
                field.options.forEach(function(opt) {
                    $('<option>').val(opt).text(opt).appendTo(input);
                });
                input.val(variant[field.key] || '');
            } else if (field.type === 'textarea') {
                input = $('<textarea>').val(variant[field.key] || '');
            } else {
                input = $('<input>').attr('type', field.type).val(variant[field.key] || '');
            }
            
            input.attr('data-card', cardName)
                 .attr('data-index', index)
                 .attr('data-field', field.key);
            
            fieldDiv.append(label).append(input);
            variantDiv.append(fieldDiv);
        });
        
        // 删除按钮
        var deleteButton = $('<button>').text('删除').click(function() {
            deleteCardVariant(cardName, index);
        });
        variantDiv.append(deleteButton);
        
        return variantDiv;
    }

    // 添加新卡牌
    function addNewCard() {
        var cardName = prompt('输入新卡牌名称:');
        if (!cardName) return;
        
        cardData[cardName] = [{
            art: '',
            '卡组': '',
            '属性': '',
            '稀有度': '',
            'AP': 1,
            '类型': '',
            '机制': '',
            '描述': '',
            '衍生卡牌': ''
        }];
        
        displayCards(cardData, Object.keys(cardData));
    }

    // 添加卡牌变体
    function addCardVariant(cardName) {
        if (!cardData[cardName]) {
            cardData[cardName] = [];
        }
        
        cardData[cardName].push({
            art: '',
            '卡组': '',
            '属性': '',
            '稀有度': '',
            'AP': 1,
            '类型': '',
            '机制': '',
            '描述': '',
            '衍生卡牌': ''
        });
        
        displayCards(cardData, Object.keys(cardData));
    }

    // 删除卡牌变体
    function deleteCardVariant(cardName, index) {
        if (confirm('确认删除这个变体?')) {
            cardData[cardName].splice(index, 1);
            if (cardData[cardName].length === 0) {
                delete cardData[cardName];
            }
            displayCards(cardData, Object.keys(cardData));
        }
    }

    // 保存数据
    function saveCardData() {
        if (!currentCharacter) {
            mw.notify('请先选择角色', { type: 'warning' });
            return;
        }
        
        // 收集表单数据更新cardData
        $('#cards-container input, #cards-container select, #cards-container textarea').each(function() {
            var $this = $(this);
            var cardName = $this.data('card');
            var index = $this.data('index');
            var field = $this.data('field');
            var value = $this.val();
            
            if (cardData[cardName] && cardData[cardName][index]) {
                if (field === 'AP') {
                    value = parseInt(value) || 0;
                }
                if (value) {
                    cardData[cardName][index][field] = value;
                } else {
                    delete cardData[cardName][index][field];
                }
            }
        });
        
        var moduleContent = generateModuleContent(cardData);
        
        api.postWithToken('csrf', {
            action: 'edit',
            title: '模块:卡牌/' + currentCharacter,
            text: moduleContent,
            summary: '通过卡牌管理器更新'
        }).done(function() {
            mw.notify('保存成功!', { type: 'success' });
        }).fail(function(code, data) {
            mw.notify('保存失败: ' + (data.error ? data.error.info : code), { type: 'error' });
        });
    }

    // 生成模块内容
    function generateModuleContent(data) {
        var content = 'local p = {}\n\n';
        
        // 生成cardOrder
        content += 'local cardOrder = {\n';
        Object.keys(data).forEach(function(cardName) {
            content += '    "' + cardName + '",\n';
        });
        content += '}\n\n';
        
        // 生成card表
        content += 'local card = {\n';
        Object.keys(data).forEach(function(cardName) {
            content += '    ["' + cardName + '"] = {\n';
            
            data[cardName].forEach(function(variant) {
                content += '        {\n';
                Object.keys(variant).forEach(function(key) {
                    var value = variant[key];
                    if (value !== null && value !== undefined && value !== '') {
                        if (key === 'AP' || !isNaN(value)) {
                            content += '            ["' + key + '"] = ' + value + ',\n';
                        } else {
                            content += '            ["' + key + '"] = "' + value.replace(/"/g, '\\"') + '",\n';
                        }
                    }
                });
                content += '        },\n';
            });
            
            content += '    },\n';
        });
        content += '}\n\n';
        
        content += 'p.card = card\n';
        content += 'p.cardOrder = cardOrder\n\n';
        content += 'return p\n';
        
        return content;
    }

    // 初始化页面
    $(function() {
        loadAllCardModules();
        
        // 绑定事件
        $('#character-select').on('change', function() {
            var characterName = $(this).val();
            if (characterName) {
                loadCharacterCards(characterName);
            }
        });
        
        $('#add-card-btn').click(addNewCard);
        $('#save-btn').click(saveCardData);
        $('#refresh-btn').click(loadAllCardModules);
    });

})();