MediaWiki

Card.js:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
无编辑摘要
律Rhyme留言 | 贡献
无编辑摘要
第1行: 第1行:
// MediaWiki:Card.js
(function() {
(function() {
     'use strict';
     'use strict';
   
 
     // 加载CSS
     // 加载CSS
     mw.loader.load('/index.php?title=Template:Card.css&action=raw&ctype=text/css', 'text/css');
     mw.loader.load('/index.php?title=Mediawiki:Card.css&action=raw&ctype=text/css', 'text/css');
   
 
     // 主管理器对象
     // 卡牌管理器类
     const CardManager = {
     class CardManager {
         currentFighter: '',
         constructor() {
        cardData: {},
            this.currentFighter = '';
        cardList: [],
            this.cards = {};
          
            this.currentCard = null;
         init: function() {
            this.fighters = [];
             this.createInterface();
           
             this.loadFighters();
            // 默认数据
            this.defaultData = {
                order: [],
                ego: ''
            };
           
            // 当前编辑的卡牌数据
            this.cardData = {
                name: '',
                displayname: '',
                art: '',
                group: '',
                rarity: '',
                god: '',
                ap: '',
                type: '攻击',
                dict: '',
                desc_global: '',
                sub: '',
                isinspiration: false,
                isgod_inspiration: false,
                inspirations: [],
                god_inspirations: {
                    circen: [],
                    diallos: [],
                    nihilum: [],
                    secred: [],
                    vitor: []
                }
            };
        }
 
         // 初始化
         async init() {
             await this.loadFighters();
             this.render();
             this.bindEvents();
             this.bindEvents();
         },
         }
          
 
         createInterface: function() {
         // 加载战斗员列表
             const container = $('<div>').attr('id', 'card-manager').addClass('card-manager-container');
         async loadFighters() {
             try {
                const api = new mw.Api();
                const response = await api.get({
                    action: 'query',
                    list: 'categorymembers',
                    cmtitle: 'Category:战斗员',
                    cmlimit: 500
                });
               
                this.fighters = response.query.categorymembers.map(page => page.title);
            } catch (error) {
                console.error('加载战斗员列表失败:', error);
                this.fighters = [];
            }
        }
 
        // 渲染主界面
        render() {
            const container = this.createDiv('card-manager');
              
              
             // 创建三列布局
             // 左侧面板
             const leftPanel = this.createLeftPanel();
             const leftPanel = this.createDiv('card-input-panel');
             const centerPanel = this.createCenterPanel();
             leftPanel.appendChild(this.renderFighterSelect());
             const rightPanel = this.createRightPanel();
            leftPanel.appendChild(this.renderDefaultInfo());
             leftPanel.appendChild(this.renderCardInput());
              
              
             container.append(leftPanel, centerPanel, rightPanel);
             // 中间面板
             $('#mw-content-text').prepend(container);
             const middlePanel = this.createDiv('card-list-panel');
        },
             middlePanel.appendChild(this.renderCardLists());
       
        createLeftPanel: function() {
             const panel = $('<div>').addClass('card-panel card-panel-left');
              
              
             // 战斗员选择
             // 右侧面板
             const fighterSection = $('<div>').addClass('card-section');
             const rightPanel = this.createDiv('card-preview-panel');
             fighterSection.append(
             rightPanel.appendChild(this.renderPreview());
                $('<div>').addClass('section-title').text('战斗员选择'),
           
                $('<div>').addClass('form-group').append(
            container.appendChild(leftPanel);
                    $('<div>').addClass('form-label').text('当前战斗员:'),
            container.appendChild(middlePanel);
                    $('<div>').attr('id', 'fighter-select').addClass('custom-select').append(
            container.appendChild(rightPanel);
                        $('<div>').addClass('select-display').text('请选择战斗员'),
           
                        $('<div>').addClass('select-options').hide()
            // 添加到页面
                     )
            const content = document.getElementById('mw-content-text');
                 )
            if (content) {
                content.innerHTML = '';
                content.appendChild(container);
            }
        }
 
        // 创建div元素
        createDiv(className, text = '') {
            const div = document.createElement('div');
            if (className) div.className = className;
            if (text) div.textContent = text;
            return div;
        }
 
        // 渲染战斗员选择
        renderFighterSelect() {
            const container = this.createDiv('form-group');
           
            const label = this.createDiv('form-label', '当前战斗员');
            container.appendChild(label);
           
            const select = this.createCustomSelect(
                this.fighters,
                this.currentFighter,
                (value) => {
                     this.currentFighter = value;
                    this.loadFighterData();
                 }
             );
             );
              
              
             // 默认信息区
             container.appendChild(select);
             const defaultInfo = $('<div>').addClass('card-section');
            return container;
             defaultInfo.append(
        }
                $('<div>').addClass('section-title').text('默认信息'),
 
                 this.createInput('card-order', '卡牌顺序', ',,,虚无残影,消灭烙印,黑洞,虚妄的誓约,无忧的回声'),
        // 渲染默认信息区
                 this.createInput('ego', '属性', '虚无')
        renderDefaultInfo() {
             );
             const container = this.createDiv('default-info-section');
            const title = this.createDiv('section-title', '默认信息');
             container.appendChild(title);
           
            // 卡牌顺序
            const orderGroup = this.createDiv('form-group');
            const orderLabel = this.createDiv('form-label', '卡牌顺序(card.order)');
            const orderInput = this.createInput('text', this.defaultData.order.join(','), (value) => {
                 this.defaultData.order = value.split(',').map(s => s.trim()).filter(s => s);
                this.updatePreview();
            });
            orderGroup.appendChild(orderLabel);
            orderGroup.appendChild(orderInput);
            container.appendChild(orderGroup);
           
            // 属性
            const egoGroup = this.createDiv('form-group');
            const egoLabel = this.createDiv('form-label', '属性(ego)');
            const egoInput = this.createInput('text', this.defaultData.ego, (value) => {
                this.defaultData.ego = value;
                this.updatePreview();
            });
            egoGroup.appendChild(egoLabel);
            egoGroup.appendChild(egoInput);
            container.appendChild(egoGroup);
           
            return container;
        }
 
        // 渲染卡牌输入区
        renderCardInput() {
            const container = this.createDiv();
            const title = this.createDiv('section-title', '卡牌数据');
            container.appendChild(title);
           
            // 卡牌名称
            container.appendChild(this.createFormGroup('卡牌名称',  
                this.createInput('text', this.cardData.name, (value) => {
                    this.cardData.name = value;
                    this.updatePreview();
                })
            ));
           
            // 显示名称
            container.appendChild(this.createFormGroup('显示名称(displayname)',  
                this.createInput('text', this.cardData.displayname, (value) => {
                    this.cardData.displayname = value;
                    this.updatePreview();
                })
            ));
           
            // 图片
            container.appendChild(this.createFormGroup('图片(art)',  
                 this.createInput('text', this.cardData.art, (value) => {
                    this.cardData.art = value;
                    this.updatePreview();
                })
            ));
           
            // 卡组
            container.appendChild(this.createFormGroup('卡组(group)',  
                this.createGroupSelect()
             ));
              
              
             // 卡牌数据输入区
             // 稀有度
             const cardDataSection = $('<div>').addClass('card-section');
             container.appendChild(this.createFormGroup('稀有度(rarity)',  
            cardDataSection.append(
                 this.createRaritySelect()
                $('<div>').addClass('section-title').text('卡牌数据'),
            ));
                this.createInput('card-name', '卡牌名称', '黑洞'),
                 this.createInput('displayname', '显示名称', ''),
                this.createInput('art', '图片', 'unique_1064_02.png'),
                this.createDropdown('group', '卡组', ['自我意识技能', '起始卡牌', '独特卡牌', '灵光一闪', '神光一闪']),
                this.createDropdown('rarity', '稀有度', ['白', '蓝', '橙', '彩']),
                this.createDropdown('god', '神明', ['circen', 'diallos', 'nihilum', 'secred', 'vitor']),
                this.createInput('ap', 'AP', '2'),
                this.createDropdown('type', '卡牌类型', ['攻击', '技能', '强化']),
                this.createInput('dict', '机制', ''),
                this.createDescriptionInput(),
                this.createInput('sub', '衍生卡牌', ''),
                this.createCheckbox('isinspiration', '是否存在灵光一闪'),
                this.createCheckbox('god_inspiration', '是否存在神光一闪')
            );
              
              
             panel.append(fighterSection, defaultInfo, cardDataSection);
             // 神明
            return panel;
            container.appendChild(this.createFormGroup('神明',  
        },
                this.createGodSelect()
       
             ));
        createCenterPanel: function() {
             const panel = $('<div>').addClass('card-panel card-panel-center');
              
              
             // 卡牌列表
             // AP
             const cardListSection = $('<div>').addClass('card-section');
             container.appendChild(this.createFormGroup('AP',
            cardListSection.append(
                this.createInput('text', this.cardData.ap, (value) => {
                $('<div>').addClass('section-title').text('卡牌列表'),
                    this.cardData.ap = value;
                 $('<div>').attr('id', 'card-list').addClass('card-list')
                    this.updatePreview();
             );
                 })
             ));
              
              
             // 灵光一闪列表
             // 卡牌类型
             const inspirationSection = $('<div>').addClass('card-section');
             container.appendChild(this.createFormGroup('卡牌类型(type)',  
            inspirationSection.append(
                 this.createTypeSelect()
                $('<div>').addClass('section-title').text('灵光一闪列表'),
             ));
                 $('<div>').attr('id', 'inspiration-list').addClass('card-list')
             );
              
              
             // 神光一闪列表
             // 机制
             const godInspirationSection = $('<div>').addClass('card-section');
             container.appendChild(this.createFormGroup('机制(dict)',
            godInspirationSection.append(
                this.createInput('text', this.cardData.dict, (value) => {
                $('<div>').addClass('section-title').text('神光一闪列表'),
                    this.cardData.dict = value;
                 $('<div>').attr('id', 'god-inspiration-list').addClass('card-list')
                    this.updatePreview();
             );
                 })
             ));
              
              
             // 操作按钮
             // 描述
             const buttonSection = $('<div>').addClass('card-section button-group');
             const descGroup = this.createDiv('form-group');
             buttonSection.append(
             const descLabel = this.createDiv('form-label', '描述(desc_global)');
                $('<div>').addClass('card-button button-add').text('添加卡牌'),
            descGroup.appendChild(descLabel);
                $('<div>').addClass('card-button button-update').text('更新卡牌'),
            descGroup.appendChild(this.createFormatButtons());
                $('<div>').addClass('card-button button-delete').text('删除卡牌'),
            descGroup.appendChild(this.createTextarea(this.cardData.desc_global, (value) => {
                 $('<div>').addClass('card-button button-save').text('保存到模块')
                this.cardData.desc_global = value;
             );
                 this.updatePreview();
            }));
             container.appendChild(descGroup);
              
              
             panel.append(cardListSection, inspirationSection, godInspirationSection, buttonSection);
             // 衍生卡牌
            return panel;
            container.appendChild(this.createFormGroup('衍生卡牌(sub)',  
        },
                this.createInput('text', this.cardData.sub, (value) => {
       
                    this.cardData.sub = value;
        createRightPanel: function() {
                    this.updatePreview();
             const panel = $('<div>').addClass('card-panel card-panel-right');
                })
             ));
              
              
             const previewSection = $('<div>').addClass('card-section');
             // 是否存在灵光一闪
             previewSection.append(
             container.appendChild(this.createFormGroup('是否存在灵光一闪',  
                $('<div>').addClass('section-title').text('Lua代码预览'),
                 this.createCheckbox(this.cardData.isinspiration, (checked) => {
                 $('<div>').addClass('code-preview-wrapper').append(
                    this.cardData.isinspiration = checked;
                     $('<pre>').attr('id', 'lua-preview').addClass('lua-preview')
                     this.updatePreview();
                 )
                 })
             );
             ));
              
              
             panel.append(previewSection);
             // 是否存在神光一闪
            return panel;
             container.appendChild(this.createFormGroup('是否存在神光一闪',  
        },
                 this.createCheckbox(this.cardData.isgod_inspiration, (checked) => {
       
                     this.cardData.isgod_inspiration = checked;
        createInput: function(id, label, placeholder) {
                     this.updatePreview();
             return $('<div>').addClass('form-group').append(
                 })
                $('<div>').addClass('form-label').text(label + ''),
             ));
                 $('<div>').attr('id', id).addClass('custom-input').attr('contenteditable', 'true')
                    .attr('data-placeholder', placeholder || '')
            );
        },
       
        createDropdown: function(id, label, options) {
            const dropdown = $('<div>').addClass('form-group').append(
                $('<div>').addClass('form-label').text(label + ':'),
                $('<div>').attr('id', id).addClass('custom-select').append(
                     $('<div>').addClass('select-display').text(options[0]),
                     $('<div>').addClass('select-options').hide()
                 )
             );
              
              
             const optionsContainer = dropdown.find('.select-options');
            // 按钮组
             options.forEach(opt => {
             const btnGroup = this.createDiv('btn-group');
                optionsContainer.append(
            const saveBtn = this.createDiv('btn btn-primary', '保存卡牌');
                    $('<div>').addClass('select-option').text(opt)
             saveBtn.onclick = () => this.saveCard();
                );
            const newBtn = this.createDiv('btn btn-success', '新建卡牌');
             });
            newBtn.onclick = () => this.newCard();
            btnGroup.appendChild(saveBtn);
            btnGroup.appendChild(newBtn);
             container.appendChild(btnGroup);
              
              
             return dropdown;
             return container;
         },
         }
          
 
         createCheckbox: function(id, label) {
         // 创建表单组
             return $('<div>').addClass('form-group').append(
         createFormGroup(label, input) {
                $('<div>').addClass('form-label').text(label + ':'),
             const group = this.createDiv('form-group');
                $('<div>').attr('id', id).addClass('custom-checkbox').append(
            const labelDiv = this.createDiv('form-label', label);
                    $('<div>').addClass('checkbox-box'),
            group.appendChild(labelDiv);
                    $('<div>').addClass('checkbox-label').text('否')
            group.appendChild(input);
                ).data('checked', false)
             return group;
             );
         }
         },
 
          
         // 创建自定义下拉框
         createDescriptionInput: function() {
         createCustomSelect(options, selected, onChange) {
             const descGroup = $('<div>').addClass('form-group');
             const container = this.createDiv('custom-select');
              
              
            // 工具栏
             const display = this.createDiv('select-display', selected || '请选择...');
             const toolbar = $('<div>').addClass('desc-toolbar').append(
            const arrow = this.createDiv('select-arrow', '');
                $('<div>').addClass('toolbar-btn').text('蓝色文本').data('format', 'blue'),
            display.appendChild(arrow);
                $('<div>').addClass('toolbar-btn').text('绿色文本').data('format', 'green'),
                $('<div>').addClass('toolbar-btn').text('绿色描边').data('format', 'outline'),
                $('<div>').addClass('toolbar-btn').text('词典').data('format', 'dict'),
                $('<div>').addClass('toolbar-btn').text('换行').data('format', 'br')
            );
              
              
             descGroup.append(
             const dropdown = this.createDiv('select-dropdown');
                $('<div>').addClass('form-label').text('描述:'),
                toolbar,
                $('<div>').attr('id', 'desc_global').addClass('custom-textarea')
                    .attr('contenteditable', 'true')
                    .html('伤害{{文本|蓝|240}}%<br>按照消灭卡牌的数量,伤害量+{{文本|蓝|40}}%<br>(最多{{文本|蓝|10}}次)')
            );
              
              
             return descGroup;
             options.forEach(option => {
        },
                const optionDiv = this.createDiv('select-option', option);
       
                 if (option === selected) {
        loadFighters: function() {
                    optionDiv.classList.add('selected');
            // 通过API加载战斗员分类的页面
                 }
            new mw.Api().get({
                 optionDiv.onclick = () => {
                action: 'query',
                    display.childNodes[0].textContent = option;
                 list: 'categorymembers',
                    dropdown.querySelectorAll('.select-option').forEach(o => o.classList.remove('selected'));
                cmtitle: 'Category:战斗员',
                     optionDiv.classList.add('selected');
                 cmlimit: 500,
                    dropdown.classList.remove('active');
                 format: 'json'
                     onChange(option);
            }).done(function(data) {
                 };
                const fighterSelect = $('#fighter-select .select-options');
                dropdown.appendChild(optionDiv);
                fighterSelect.empty();
               
                data.query.categorymembers.forEach(function(member) {
                     fighterSelect.append(
                        $('<div>').addClass('select-option').text(member.title).data('fighter', member.title)
                     );
                 });
             });
             });
        },
       
        bindEvents: function() {
            const self = this;
              
              
             // 下拉框事件
             display.onclick = () => {
            $(document).on('click', '.custom-select', function(e) {
                 dropdown.classList.toggle('active');
                 e.stopPropagation();
             };
                const options = $(this).find('.select-options');
                $('.select-options').not(options).hide();
                options.toggle();
             });
              
              
             $(document).on('click', '.select-option', function(e) {
             // 点击外部关闭
                 e.stopPropagation();
            document.addEventListener('click', (e) => {
                const select = $(this).closest('.custom-select');
                 if (!container.contains(e.target)) {
                const display = select.find('.select-display');
                     dropdown.classList.remove('active');
                display.text($(this).text());
                $(this).parent().hide();
               
                if (select.attr('id') === 'fighter-select') {
                     self.currentFighter = $(this).data('fighter');
                    self.loadFighterCards();
                 }
                 }
             });
             });
              
              
             // 复选框事件
             container.appendChild(display);
            $(document).on('click', '.custom-checkbox', function() {
            container.appendChild(dropdown);
                const isChecked = !$(this).data('checked');
           
                $(this).data('checked', isChecked);
            return container;
                 $(this).find('.checkbox-box').toggleClass('checked');
        }
                $(this).find('.checkbox-label').text(isChecked ? '是' : '否');
 
        // 创建输入框
        createInput(type, value, onChange) {
            const input = this.createDiv('custom-input');
            input.contentEditable = true;
            input.textContent = value;
            input.oninput = () => onChange(input.textContent);
            return input;
        }
 
        // 创建文本域
        createTextarea(value, onChange) {
            const textarea = this.createDiv('custom-textarea');
            textarea.contentEditable = true;
            textarea.innerHTML = value.replace(/<br>/g, '\n');
            textarea.oninput = () => onChange(textarea.textContent);
            return textarea;
        }
 
        // 创建格式化按钮
        createFormatButtons() {
            const container = this.createDiv('format-buttons');
           
            const buttons = [
                { label: '蓝色文本', class: 'blue', template: '{{文本|蓝|%s}}' },
                { label: '绿色文本', class: 'green', template: '{{文本|绿|%s}}' },
                 { label: '绿色描边', class: 'green', template: '{{描边|绿|%s}}' },
                { label: '词典', class: '', template: '{{词典|%s}}' },
                { label: '换行', class: '', template: '<br>' }
            ];
           
            buttons.forEach(btn => {
                const button = this.createDiv(`format-btn ${btn.class}`, btn.label);
                button.onclick = () => {
                    const textarea = button.parentElement.nextElementSibling;
                    this.insertTemplate(textarea, btn.template);
                };
                container.appendChild(button);
             });
             });
              
              
             // 描述工具栏事件
             return container;
             $(document).on('click', '.toolbar-btn', function() {
        }
                 const format = $(this).data('format');
 
                 const textarea = $('#desc_global')[0];
        // 插入模板
                const selection = window.getSelection();
        insertTemplate(textarea, template) {
                 const selectedText = selection.toString();
             const selection = window.getSelection();
                  
            const selectedText = selection.toString();
                 let insertText = '';
           
                 switch(format) {
            if (template === '<br>') {
                    case 'blue':
                const text = textarea.textContent;
                        insertText = selectedText ? `{{文本|蓝|${selectedText}}}` : '{{文本|蓝|}}';
                const pos = this.getCaretPosition(textarea);
                        break;
                textarea.textContent = text.slice(0, pos) + '\n' + text.slice(pos);
                    case 'green':
            } else {
                        insertText = selectedText ? `{{文本|绿|${selectedText}}}` : '{{文本|绿|}}';
                 const result = template.replace('%s', selectedText || '选择文字');
                        break;
                if (selectedText) {
                    case 'outline':
                    document.execCommand('insertText', false, result);
                        insertText = selectedText ? `{{描边|绿|${selectedText}}}` : '{{描边|绿|}}';
                 } else {
                        break;
                    const text = textarea.textContent;
                    case 'dict':
                    const pos = this.getCaretPosition(textarea);
                        insertText = selectedText ? `{{词典|${selectedText}}}` : '{{词典|}}';
                    textarea.textContent = text.slice(0, pos) + result + text.slice(pos);
                        break;
                }
                    case 'br':
            }
                        insertText = '<br>';
           
                        break;
            textarea.dispatchEvent(new Event('input'));
        }
 
        // 获取光标位置
        getCaretPosition(element) {
            const selection = window.getSelection();
            if (selection.rangeCount > 0) {
                 const range = selection.getRangeAt(0);
                const preCaretRange = range.cloneRange();
                 preCaretRange.selectNodeContents(element);
                 preCaretRange.setEnd(range.endContainer, range.endOffset);
                 return preCaretRange.toString().length;
            }
            return 0;
        }
 
        // 创建复选框
        createCheckbox(checked, onChange) {
            const container = this.createDiv('checkbox-group');
            const checkbox = this.createDiv('custom-checkbox');
            if (checked) checkbox.classList.add('checked');
           
            const label = this.createDiv('', '');
           
            checkbox.onclick = () => {
                checkbox.classList.toggle('checked');
                const isChecked = checkbox.classList.contains('checked');
                label.textContent = isChecked ? '是' : '否';
                onChange(isChecked);
            };
           
            container.appendChild(checkbox);
            container.appendChild(label);
            return container;
        }
 
        // 创建卡组选择
        createGroupSelect() {
            const container = this.createDiv('group-options');
            const groups = ['自我意识技能', '起始卡牌', '独特卡牌', '灵光一闪', '神光一闪'];
           
            groups.forEach(group => {
                const option = this.createDiv('group-option', group);
                if (this.cardData.group === group) {
                    option.classList.add('selected');
                 }
                 }
                  
                 option.onclick = () => {
                document.execCommand('insertHTML', false, insertText);
                    container.querySelectorAll('.group-option').forEach(o => o.classList.remove('selected'));
                    option.classList.add('selected');
                    this.cardData.group = group;
                    this.updatePreview();
                };
                container.appendChild(option);
             });
             });
              
              
             // 按钮事件
             return container;
             $('.button-add').on('click', function() {
        }
                 self.addCard();
 
        // 创建稀有度选择
        createRaritySelect() {
             const container = this.createDiv('rarity-options');
            const rarities = ['白', '蓝', '橙', '彩'];
           
            rarities.forEach(rarity => {
                const option = this.createDiv('rarity-option', rarity);
                if (this.cardData.rarity === rarity) {
                    option.classList.add('selected');
                }
                option.onclick = () => {
                    container.querySelectorAll('.rarity-option').forEach(o => o.classList.remove('selected'));
                    option.classList.add('selected');
                    this.cardData.rarity = rarity;
                    this.updatePreview();
                };
                 container.appendChild(option);
             });
             });
              
              
             $('.button-update').on('click', function() {
             return container;
                 self.updateCard();
        }
 
        // 创建神明选择
        createGodSelect() {
            const container = this.createDiv('god-options');
            const gods = ['circen', 'diallos', 'nihilum', 'secred', 'vitor'];
           
            gods.forEach(god => {
                const option = this.createDiv('god-option', god);
                if (this.cardData.god === god) {
                    option.classList.add('selected');
                }
                option.onclick = () => {
                    container.querySelectorAll('.god-option').forEach(o => o.classList.remove('selected'));
                    option.classList.add('selected');
                    this.cardData.god = god;
                    this.updatePreview();
                };
                 container.appendChild(option);
             });
             });
              
              
             $('.button-delete').on('click', function() {
             return container;
                 self.deleteCard();
        }
 
        // 创建类型选择
        createTypeSelect() {
            const container = this.createDiv('type-options');
            const types = ['攻击', '技能', '强化'];
           
            types.forEach(type => {
                const option = this.createDiv('type-option', type);
                if (this.cardData.type === type) {
                    option.classList.add('selected');
                }
                option.onclick = () => {
                    container.querySelectorAll('.type-option').forEach(o => o.classList.remove('selected'));
                    option.classList.add('selected');
                    this.cardData.type = type;
                    this.updatePreview();
                };
                 container.appendChild(option);
             });
             });
              
              
             $('.button-save').on('click', function() {
             return container;
                self.saveToModule();
        }
             });
 
        // 渲染卡牌列表
        renderCardLists() {
            const container = this.createDiv();
           
            // 卡牌列表
            const cardListTitle = this.createDiv('panel-title', '卡牌列表');
            container.appendChild(cardListTitle);
           
            const cardListContainer = this.createDiv('list-container');
            cardListContainer.id = 'card-list';
            this.updateCardList(cardListContainer);
             container.appendChild(cardListContainer);
              
              
             // 输入变化时更新预览
             return container;
            $(document).on('input', '.custom-input, .custom-textarea', function() {
        }
                self.updatePreview();
 
            });
        // 更新卡牌列表
        updateCardList(container) {
            container.innerHTML = '';
              
              
             // 点击其他地方关闭下拉框
             if (Object.keys(this.cards).length === 0) {
            $(document).on('click', function() {
                container.appendChild(this.createDiv('list-empty', '暂无卡牌'));
                $('.select-options').hide();
            });
        },
       
        addCard: function() {
            const cardName = $('#card-name').text();
            if (!cardName) {
                mw.notify('请输入卡牌名称', {type: 'error'});
                 return;
                 return;
             }
             }
              
              
             const cardData = this.getFormData();
             Object.keys(this.cards).forEach(name => {
            this.cardData[cardName] = cardData;
                const card = this.cards[name];
             this.updateCardList();
                const item = this.createDiv('card-list-item');
               
                const info = this.createDiv();
                const nameDiv = this.createDiv('card-list-item-name', name);
                const detailDiv = this.createDiv('card-list-item-info',
                    `${card.type || '攻击'} | AP:${card.ap || 0} | ${card.rarity || ''}`
                );
                info.appendChild(nameDiv);
                info.appendChild(detailDiv);
               
                const deleteBtn = this.createDiv('delete-btn', '删除');
                deleteBtn.onclick = (e) => {
                    e.stopPropagation();
                    if (confirm(`确定要删除卡牌"${name}"吗?`)) {
                        delete this.cards[name];
                        this.updateCardList(container);
                        this.updatePreview();
                       
                        // 如果删除的是当前编辑的卡牌,清空表单
                        if (this.currentCard === name) {
                            this.newCard();
                        }
                    }
                };
               
                item.appendChild(info);
                item.appendChild(deleteBtn);
               
                item.onclick = () => {
                    this.loadCard(name);
                    container.querySelectorAll('.card-list-item').forEach(i => i.classList.remove('active'));
                    item.classList.add('active');
                };
               
                container.appendChild(item);
            });
        }
 
        // 渲染预览
        renderPreview() {
            const container = this.createDiv();
            const title = this.createDiv('panel-title', 'Lua代码预览');
            container.appendChild(title);
           
             const preview = this.createDiv('preview-code');
            preview.id = 'code-preview';
            container.appendChild(preview);
           
             this.updatePreview();
             this.updatePreview();
            mw.notify('卡牌添加成功', {type: 'success'});
        },
       
        updateCard: function() {
            const cardName = $('#card-name').text();
            if (!cardName || !this.cardData[cardName]) {
                mw.notify('请选择要更新的卡牌', {type: 'error'});
                return;
            }
              
              
             const cardData = this.getFormData();
            // 添加复制按钮
             this.cardData[cardName] = cardData;
             const copyBtn = this.createDiv('btn btn-primary', '复制代码');
             this.updateCardList();
             copyBtn.style.marginTop = '10px';
             this.updatePreview();
             copyBtn.onclick = () => this.copyCode();
             mw.notify('卡牌更新成功', {type: 'success'});
             container.appendChild(copyBtn);
         },
              
          
            return container;
         deleteCard: function() {
         }
             const cardName = $('#card-name').text();
 
             if (!cardName || !this.cardData[cardName]) {
         // 更新预览
                mw.notify('请选择要删除的卡牌', {type: 'error'});
         updatePreview() {
                return;
             const preview = document.getElementById('code-preview');
            }
             if (!preview) return;
              
              
             delete this.cardData[cardName];
             preview.textContent = this.generateLuaCode();
            this.updateCardList();
        }
            this.updatePreview();
 
            this.clearForm();
         // 生成Lua代码
            mw.notify('卡牌删除成功', {type: 'success'});
         generateLuaCode() {
        },
             let code = 'local card = {}\n\n';
          
         getFormData: function() {
             const data = {
                base: {
                    displayname: $('#displayname').text(),
                    art: $('#art').text(),
                    group: $('#group .select-display').text(),
                    rarity: $('#rarity .select-display').text(),
                    ap: $('#ap').text(),
                    type: $('#type .select-display').text(),
                    dict: $('#dict').text(),
                    desc_global: $('#desc_global').html(),
                    sub: $('#sub').text(),
                    isinspiration: $('#isinspiration').data('checked') ? 1 : 0,
                    god_inspiration: $('#god_inspiration').data('checked') ? 1 : 0
                },
                var: {}
            };
              
              
             // 如果有灵光一闪,添加默认数据
             // 生成order
             if (data.base.isinspiration) {
             if (this.defaultData.order.length > 0) {
                 data.var.inspiration = [
                 code += `card.order = { "${this.defaultData.order.join(',')}" }\n\n`;
                    { ap: 1 },
                    { desc_global: data.base.desc_global },
                    { desc_global: data.base.desc_global },
                    { ap: 3, desc_global: data.base.desc_global },
                    { ap: 1, type: '强化', desc_global: data.base.desc_global }
                ];
             }
             }
              
              
             // 如果有神光一闪,添加默认数据
             // 生成info
             if (data.base.god_inspiration) {
            code += 'card.info = {\n';
                 data.var.god_inspiration = {
             if (this.defaultData.ego) {
                    circen: [{ ap: 1 }],
                 code += `    ego = "${this.defaultData.ego}",\n`;
                    diallos: [{ ap: 1 }],
                    nihilum: [{ ap: 1 }],
                    secred: [{ ap: 1 }],
                    vitor: [{ ap: 1 }]
                };
             }
             }
            code += '}\n\n';
              
              
             return data;
             // 生成各个卡牌
        },
             Object.keys(this.cards).forEach(name => {
       
                 const card = this.cards[name];
        updateCardList: function() {
                 code += this.generateCardCode(name, card);
            const cardList = $('#card-list');
            cardList.empty();
           
             Object.keys(this.cardData).forEach(cardName => {
                 const card = this.cardData[cardName];
                 const cardItem = $('<div>').addClass('card-item').text(cardName);
                cardItem.on('click', () => this.loadCard(cardName));
                cardList.append(cardItem);
               
                // 更新灵光一闪列表
                if (card.base.isinspiration) {
                    const inspirationItem = $('<div>').addClass('card-item inspiration-item')
                        .text(cardName + ' - 灵光一闪');
                    $('#inspiration-list').append(inspirationItem);
                }
               
                // 更新神光一闪列表
                if (card.base.god_inspiration) {
                    const godItem = $('<div>').addClass('card-item god-item')
                        .text(cardName + ' - 神光一闪');
                    $('#god-inspiration-list').append(godItem);
                }
             });
             });
        },
       
        loadCard: function(cardName) {
            const card = this.cardData[cardName];
            if (!card) return;
              
              
             $('#card-name').text(cardName);
             code += 'return card';
            $('#displayname').text(card.base.displayname || '');
            $('#art').text(card.base.art || '');
            $('#group .select-display').text(card.base.group || '');
            $('#rarity .select-display').text(card.base.rarity || '');
            $('#ap').text(card.base.ap || '');
            $('#type .select-display').text(card.base.type || '');
            $('#dict').text(card.base.dict || '');
            $('#desc_global').html(card.base.desc_global || '');
            $('#sub').text(card.base.sub || '');
              
              
             const inspirationChecked = card.base.isinspiration === 1;
             return code;
            $('#isinspiration').data('checked', inspirationChecked);
        }
             $('#isinspiration .checkbox-box').toggleClass('checked', inspirationChecked);
 
             $('#isinspiration .checkbox-label').text(inspirationChecked ? '是' : '否');
        // 生成单个卡牌代码
        generateCardCode(name, card) {
             let code = `card["${name}"] = {\n`;
             code += '   base = {\n';
              
              
             const godChecked = card.base.god_inspiration === 1;
             // 基础属性
             $('#god_inspiration').data('checked', godChecked);
            if (card.displayname) {
             $('#god_inspiration .checkbox-box').toggleClass('checked', godChecked);
                code += `        displayname = "${card.displayname}",\n`;
             $('#god_inspiration .checkbox-label').text(godChecked ? '是' : '否');
             }
        },
            if (card.art) {
       
                code += `        art = "${card.art}",\n`;
        clearForm: function() {
             }
            $('.custom-input').text('');
            if (card.group) {
             $('.custom-textarea').html('');
                code += `        group = "${card.group}",\n`;
             $('.custom-checkbox').data('checked', false);
             }
             $('.checkbox-box').removeClass('checked');
            if (card.rarity) {
            $('.checkbox-label').text('');
                code += `        rarity = "${card.rarity}",\n`;
        },
            }
       
            if (card.ap) {
        updatePreview: function() {
                code += `        ap = ${isNaN(card.ap) ? `"${card.ap}"` : card.ap},\n`;
            const cardOrder = $('#card-order').text();
             }
             const ego = $('#ego').text();
            if (card.type) {
                code += `        type = "${card.type}",\n`;
             }
            if (card.dict) {
                code += `        dict = "${card.dict}",\n`;
             }
            if (card.desc_global) {
                const desc = card.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"');
                code += `        desc_global = "${desc}",\n`;
            }
            if (card.sub) {
                code += `        sub = "${card.sub}",\n`;
            }
            if (card.isinspiration) {
                code += `        isinspiration = 1,\n`;
             }
            if (card.isgod_inspiration) {
                code += `        isgod_inspiration = 1,\n`;
            }
              
              
             let luaCode = 'local card = {}\n\n';
             code += '    },\n';
            luaCode += `card.order = { "${cardOrder}" }\n\n`;
            luaCode += 'card.info = {\n';
            luaCode += `   ego = "${ego}",\n`;
            luaCode += '}\n\n';
              
              
             Object.keys(this.cardData).forEach(cardName => {
             // 变体数据
                const card = this.cardData[cardName];
            if (card.isinspiration || card.isgod_inspiration) {
                luaCode += `card["${cardName}"] = {\n`;
                 code += '    var = {\n';
                 luaCode += '    base = {\n';
                  
                  
                 Object.keys(card.base).forEach(key => {
                 // 灵光一闪
                    const value = card.base[key];
                if (card.isinspiration && card.inspirations && card.inspirations.length > 0) {
                    if (value !== '' && value !== 0) {
                    code += '        inspiration = {\n';
                         if (typeof value === 'number') {
                    card.inspirations.forEach(insp => {
                             luaCode += `       ${key} = ${value},\n`;
                        code += '            {\n';
                         } else {
                        if (insp.ap !== undefined) {
                             luaCode += `       ${key} = "${value}",\n`;
                            code += `                ap = ${isNaN(insp.ap) ? `"${insp.ap}"` : insp.ap},\n`;
                        }
                         if (insp.type) {
                             code += `               type = "${insp.type}",\n`;
                         }
                        if (insp.desc_global) {
                             const desc = insp.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"');
                            code += `               desc_global = "${desc}",\n`;
                         }
                         }
                     }
                        code += '            },\n';
                 });
                     });
                    code += '        },\n';
                 }
                  
                  
                 luaCode += '    },\n';
                 // 神光一闪
               
                 if (card.isgod_inspiration && card.god_inspirations) {
                 if (card.var && Object.keys(card.var).length > 0) {
                     code += '       god_inspiration = {\n';
                     luaCode += '   var = {\n';
                     const gods = ['circen', 'diallos', 'nihilum', 'secred', 'vitor'];
                      
                     gods.forEach(god => {
                     if (card.var.inspiration) {
                        if (card.god_inspirations[god] && card.god_inspirations[god].length > 0) {
                        luaCode += '        inspiration = {\n';
                            code += `            ${god} = {\n`;
                        card.var.inspiration.forEach(insp => {
                            card.god_inspirations[god].forEach(insp => {
                            luaCode += '           {\n';
                                code += '               {\n';
                            Object.keys(insp).forEach(key => {
                                if (insp.ap !== undefined) {
                                 if (typeof insp[key] === 'number') {
                                    code += `                    ap = ${isNaN(insp.ap) ? `"${insp.ap}"` : insp.ap},\n`;
                                     luaCode += `               ${key} = ${insp[key]},\n`;
                                }
                                 } else {
                                 if (insp.type) {
                                     luaCode += `               ${key} = "${insp[key]}",\n`;
                                     code += `                   type = "${insp.type}",\n`;
                                 }
                                if (insp.desc_global) {
                                     const desc = insp.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"');
                                    code += `                   desc_global = "${desc}",\n`;
                                 }
                                 }
                                code += '                },\n';
                             });
                             });
                             luaCode += '            },\n';
                             code += '            },\n';
                         });
                         }
                        luaCode += '        },\n';
                     });
                     }
                    code += '        },\n';
                   
                    if (card.var.god_inspiration) {
                        luaCode += '        god_inspiration = {\n';
                        Object.keys(card.var.god_inspiration).forEach(god => {
                            luaCode += `            ${god} = {\n`;
                            card.var.god_inspiration[god].forEach(godInsp => {
                                luaCode += '                {\n';
                                Object.keys(godInsp).forEach(key => {
                                    if (typeof godInsp[key] === 'number') {
                                        luaCode += `                    ${key} = ${godInsp[key]},\n`;
                                    } else {
                                        luaCode += `                    ${key} = "${godInsp[key]}",\n`;
                                    }
                                });
                                luaCode += '                },\n';
                            });
                            luaCode += '            },\n';
                        });
                        luaCode += '        },\n';
                    }
                   
                    luaCode += '    },\n';
                 }
                 }
                  
                  
                 luaCode += '}\n\n';
                 code += '    },\n';
             });
            }
           
            code += '}\n\n';
           
            return code;
        }
 
        // 保存卡牌
        saveCard() {
            if (!this.cardData.name) {
                alert('请输入卡牌名称!');
                return;
             }
           
            // 克隆当前卡牌数据
            const cardToSave = JSON.parse(JSON.stringify(this.cardData));
              
              
             luaCode += 'return card';
             // 保存到cards对象
            this.cards[cardToSave.name] = cardToSave;
            this.currentCard = cardToSave.name;
              
              
             $('#lua-preview').text(luaCode);
             // 更新order
        },
            if (!this.defaultData.order.includes(cardToSave.name)) {
       
                this.defaultData.order.push(cardToSave.name);
        loadFighterCards: function() {
            }
            if (!this.currentFighter) return;
              
              
             const moduleName = `模块:卡牌/${this.currentFighter}`;
            // 更新列表和预览
             const listContainer = document.getElementById('card-list');
            if (listContainer) {
                this.updateCardList(listContainer);
            }
            this.updatePreview();
              
              
             new mw.Api().get({
             alert('卡牌保存成功!');
                 action: 'query',
        }
                 prop: 'revisions',
 
                 titles: moduleName,
        // 新建卡牌
                 rvprop: 'content',
        newCard() {
                 format: 'json'
            this.currentCard = null;
            }).done((data) => {
            this.cardData = {
                 const pages = data.query.pages;
                 name: '',
                 const pageId = Object.keys(pages)[0];
                displayname: '',
                  
                 art: '',
                 if (pageId !== '-1') {
                 group: '',
                     const content = pages[pageId].revisions[0]['*'];
                 rarity: '',
                     // 这里需要解析Lua内容并加载到界面
                 god: '',
                     this.parseLuaContent(content);
                ap: '',
                 type: '攻击',
                 dict: '',
                 desc_global: '',
                 sub: '',
                isinspiration: false,
                isgod_inspiration: false,
                inspirations: [],
                god_inspirations: {
                     circen: [],
                    diallos: [],
                    nihilum: [],
                     secred: [],
                     vitor: []
                 }
                 }
             });
             };
         },
           
          
            // 重新渲染输入区
         parseLuaContent: function(content) {
            const leftPanel = document.querySelector('.card-input-panel');
             // 简化的Lua解析,实际使用可能需要更复杂的解析器
            if (leftPanel) {
                leftPanel.innerHTML = '';
                leftPanel.appendChild(this.renderFighterSelect());
                leftPanel.appendChild(this.renderDefaultInfo());
                leftPanel.appendChild(this.renderCardInput());
            }
           
            // 清除列表选中状态
            const listContainer = document.getElementById('card-list');
            if (listContainer) {
                listContainer.querySelectorAll('.card-list-item').forEach(i => i.classList.remove('active'));
            }
         }
 
         // 加载卡牌
         loadCard(name) {
            if (!this.cards[name]) return;
           
            this.currentCard = name;
            this.cardData = JSON.parse(JSON.stringify(this.cards[name]));
           
            // 重新渲染输入区
            const leftPanel = document.querySelector('.card-input-panel');
            if (leftPanel) {
                leftPanel.innerHTML = '';
                leftPanel.appendChild(this.renderFighterSelect());
                leftPanel.appendChild(this.renderDefaultInfo());
                leftPanel.appendChild(this.renderCardInput());
             }
        }
 
        // 加载战斗员数据
        async loadFighterData() {
            if (!this.currentFighter) return;
           
             try {
             try {
                // 提取卡牌数据
                 const api = new mw.Api();
                 const cardMatches = content.matchAll(/card\["([^"]+)"\]\s*=\s*{([^}]+})}/gs);
                const moduleName = `模块:卡牌/${this.currentFighter}`;
                  
                  
                 this.cardData = {};
                 const response = await api.get({
                 for (const match of cardMatches) {
                    action: 'query',
                     const cardName = match[1];
                    prop: 'revisions',
                     // 这里需要更复杂的解析逻辑
                    titles: moduleName,
                     // 暂时使用简化版本
                    rvprop: 'content',
                    rvslots: 'main'
                });
               
                const pages = response.query.pages;
                const page = Object.values(pages)[0];
                  
                if (page.revisions) {
                     const content = page.revisions[0].slots.main['*'];
                    this.parseLuaCode(content);
                   
                     // 重新渲染
                     this.render();
                 }
                 }
               
            } catch (error) {
                 this.updateCardList();
                 console.error('加载战斗员数据失败:', error);
                this.updatePreview();
            }
             } catch (e) {
        }
                 console.error('解析Lua内容失败:', e);
 
        // 解析Lua代码(简化版)
        parseLuaCode(code) {
            // 这里应该实现完整的Lua代码解析
            // 由于复杂度较高,这里只做基本的解析示例
           
            // 解析order
            const orderMatch = code.match(/card\.order\s*=\s*{\s*"([^"]*)"\s*}/);
             if (orderMatch) {
                 this.defaultData.order = orderMatch[1].split(',').map(s => s.trim());
            }
           
            // 解析ego
            const egoMatch = code.match(/ego\s*=\s*"([^"]*)"/);
            if (egoMatch) {
                this.defaultData.ego = egoMatch[1];
             }
             }
         },
           
          
            // 这里应该继续解析各个卡牌的数据
         saveToModule: function() {
            // 由于Lua语法复杂,建议使用专门的Lua解析器
         }
 
         // 保存到Mediawiki
         async saveToMediawiki() {
             if (!this.currentFighter) {
             if (!this.currentFighter) {
                 mw.notify('请先选择战斗员', {type: 'error'});
                 alert('请先选择战斗员!');
                 return;
                 return;
             }
             }
              
              
            const code = this.generateLuaCode();
             const moduleName = `模块:卡牌/${this.currentFighter}`;
             const moduleName = `模块:卡牌/${this.currentFighter}`;
            const luaContent = $('#lua-preview').text();
              
              
             new mw.Api().postWithToken('csrf', {
             try {
                action: 'edit',
                const api = new mw.Api();
                title: moduleName,
                await api.postWithToken('csrf', {
                text: luaContent,
                    action: 'edit',
                summary: '更新卡牌数据',
                    title: moduleName,
                format: 'json'
                    text: code,
            }).done(function() {
                    summary: '通过卡牌管理器更新',
                 mw.notify('保存成功!', {type: 'success'});
                    contentmodel: 'Scribunto'
             }).fail(function(error) {
                });
                mw.notify('保存失败:' + error, {type: 'error'});
               
             });
                alert('保存成功!');
            } catch (error) {
                 console.error('保存失败:', error);
                alert('保存失败:' + error);
             }
        }
 
        // 复制代码
        copyCode() {
            const code = this.generateLuaCode();
           
            // 创建临时文本域
            const textarea = document.createElement('textarea');
            textarea.value = code;
            textarea.style.position = 'fixed';
            textarea.style.opacity = '0';
            document.body.appendChild(textarea);
           
            textarea.select();
            document.execCommand('copy');
             document.body.removeChild(textarea);
           
            alert('代码已复制到剪贴板!');
         }
         }
    };
 
   
         // 绑定事件
    // 页面加载完成后初始化
         bindEvents() {
    $(document).ready(function() {
             // 可以在这里添加全局事件监听
         // 只在特定页面加载
         if (mw.config.get('wgPageName') === 'Special:CardManager' ||
            mw.config.get('wgPageName').indexOf('卡牌管理') !== -1) {
             CardManager.init();
         }
         }
    }
    // 等待页面加载完成
    if (mw.config.get('wgPageName') === 'Special:Card' ||
        window.location.search.includes('cardmanager=1')) {
        mw.loader.using(['mediawiki.api']).then(() => {
            const manager = new CardManager();
            manager.init();
        });
    }
    // 添加导航链接(可选)
    mw.loader.using(['mediawiki.util']).then(() => {
        mw.util.addPortletLink(
            'p-tb',
            '?cardmanager=1',
            '卡牌管理器',
            't-cardmanager',
            '打开卡牌管理器'
        );
     });
     });
   
 
    // 添加到全局对象以便调试
    window.CardManager = CardManager;
})();
})();

2025年10月23日 (四) 16:05的版本

(function() {
    'use strict';

    // 加载CSS
    mw.loader.load('/index.php?title=Mediawiki:Card.css&action=raw&ctype=text/css', 'text/css');

    // 卡牌管理器类
    class CardManager {
        constructor() {
            this.currentFighter = '';
            this.cards = {};
            this.currentCard = null;
            this.fighters = [];
            
            // 默认数据
            this.defaultData = {
                order: [],
                ego: ''
            };
            
            // 当前编辑的卡牌数据
            this.cardData = {
                name: '',
                displayname: '',
                art: '',
                group: '',
                rarity: '',
                god: '',
                ap: '',
                type: '攻击',
                dict: '',
                desc_global: '',
                sub: '',
                isinspiration: false,
                isgod_inspiration: false,
                inspirations: [],
                god_inspirations: {
                    circen: [],
                    diallos: [],
                    nihilum: [],
                    secred: [],
                    vitor: []
                }
            };
        }

        // 初始化
        async init() {
            await this.loadFighters();
            this.render();
            this.bindEvents();
        }

        // 加载战斗员列表
        async loadFighters() {
            try {
                const api = new mw.Api();
                const response = await api.get({
                    action: 'query',
                    list: 'categorymembers',
                    cmtitle: 'Category:战斗员',
                    cmlimit: 500
                });
                
                this.fighters = response.query.categorymembers.map(page => page.title);
            } catch (error) {
                console.error('加载战斗员列表失败:', error);
                this.fighters = [];
            }
        }

        // 渲染主界面
        render() {
            const container = this.createDiv('card-manager');
            
            // 左侧面板
            const leftPanel = this.createDiv('card-input-panel');
            leftPanel.appendChild(this.renderFighterSelect());
            leftPanel.appendChild(this.renderDefaultInfo());
            leftPanel.appendChild(this.renderCardInput());
            
            // 中间面板
            const middlePanel = this.createDiv('card-list-panel');
            middlePanel.appendChild(this.renderCardLists());
            
            // 右侧面板
            const rightPanel = this.createDiv('card-preview-panel');
            rightPanel.appendChild(this.renderPreview());
            
            container.appendChild(leftPanel);
            container.appendChild(middlePanel);
            container.appendChild(rightPanel);
            
            // 添加到页面
            const content = document.getElementById('mw-content-text');
            if (content) {
                content.innerHTML = '';
                content.appendChild(container);
            }
        }

        // 创建div元素
        createDiv(className, text = '') {
            const div = document.createElement('div');
            if (className) div.className = className;
            if (text) div.textContent = text;
            return div;
        }

        // 渲染战斗员选择
        renderFighterSelect() {
            const container = this.createDiv('form-group');
            
            const label = this.createDiv('form-label', '当前战斗员');
            container.appendChild(label);
            
            const select = this.createCustomSelect(
                this.fighters,
                this.currentFighter,
                (value) => {
                    this.currentFighter = value;
                    this.loadFighterData();
                }
            );
            
            container.appendChild(select);
            return container;
        }

        // 渲染默认信息区
        renderDefaultInfo() {
            const container = this.createDiv('default-info-section');
            const title = this.createDiv('section-title', '默认信息');
            container.appendChild(title);
            
            // 卡牌顺序
            const orderGroup = this.createDiv('form-group');
            const orderLabel = this.createDiv('form-label', '卡牌顺序(card.order)');
            const orderInput = this.createInput('text', this.defaultData.order.join(','), (value) => {
                this.defaultData.order = value.split(',').map(s => s.trim()).filter(s => s);
                this.updatePreview();
            });
            orderGroup.appendChild(orderLabel);
            orderGroup.appendChild(orderInput);
            container.appendChild(orderGroup);
            
            // 属性
            const egoGroup = this.createDiv('form-group');
            const egoLabel = this.createDiv('form-label', '属性(ego)');
            const egoInput = this.createInput('text', this.defaultData.ego, (value) => {
                this.defaultData.ego = value;
                this.updatePreview();
            });
            egoGroup.appendChild(egoLabel);
            egoGroup.appendChild(egoInput);
            container.appendChild(egoGroup);
            
            return container;
        }

        // 渲染卡牌输入区
        renderCardInput() {
            const container = this.createDiv();
            const title = this.createDiv('section-title', '卡牌数据');
            container.appendChild(title);
            
            // 卡牌名称
            container.appendChild(this.createFormGroup('卡牌名称', 
                this.createInput('text', this.cardData.name, (value) => {
                    this.cardData.name = value;
                    this.updatePreview();
                })
            ));
            
            // 显示名称
            container.appendChild(this.createFormGroup('显示名称(displayname)', 
                this.createInput('text', this.cardData.displayname, (value) => {
                    this.cardData.displayname = value;
                    this.updatePreview();
                })
            ));
            
            // 图片
            container.appendChild(this.createFormGroup('图片(art)', 
                this.createInput('text', this.cardData.art, (value) => {
                    this.cardData.art = value;
                    this.updatePreview();
                })
            ));
            
            // 卡组
            container.appendChild(this.createFormGroup('卡组(group)', 
                this.createGroupSelect()
            ));
            
            // 稀有度
            container.appendChild(this.createFormGroup('稀有度(rarity)', 
                this.createRaritySelect()
            ));
            
            // 神明
            container.appendChild(this.createFormGroup('神明', 
                this.createGodSelect()
            ));
            
            // AP
            container.appendChild(this.createFormGroup('AP', 
                this.createInput('text', this.cardData.ap, (value) => {
                    this.cardData.ap = value;
                    this.updatePreview();
                })
            ));
            
            // 卡牌类型
            container.appendChild(this.createFormGroup('卡牌类型(type)', 
                this.createTypeSelect()
            ));
            
            // 机制
            container.appendChild(this.createFormGroup('机制(dict)', 
                this.createInput('text', this.cardData.dict, (value) => {
                    this.cardData.dict = value;
                    this.updatePreview();
                })
            ));
            
            // 描述
            const descGroup = this.createDiv('form-group');
            const descLabel = this.createDiv('form-label', '描述(desc_global)');
            descGroup.appendChild(descLabel);
            descGroup.appendChild(this.createFormatButtons());
            descGroup.appendChild(this.createTextarea(this.cardData.desc_global, (value) => {
                this.cardData.desc_global = value;
                this.updatePreview();
            }));
            container.appendChild(descGroup);
            
            // 衍生卡牌
            container.appendChild(this.createFormGroup('衍生卡牌(sub)', 
                this.createInput('text', this.cardData.sub, (value) => {
                    this.cardData.sub = value;
                    this.updatePreview();
                })
            ));
            
            // 是否存在灵光一闪
            container.appendChild(this.createFormGroup('是否存在灵光一闪', 
                this.createCheckbox(this.cardData.isinspiration, (checked) => {
                    this.cardData.isinspiration = checked;
                    this.updatePreview();
                })
            ));
            
            // 是否存在神光一闪
            container.appendChild(this.createFormGroup('是否存在神光一闪', 
                this.createCheckbox(this.cardData.isgod_inspiration, (checked) => {
                    this.cardData.isgod_inspiration = checked;
                    this.updatePreview();
                })
            ));
            
            // 按钮组
            const btnGroup = this.createDiv('btn-group');
            const saveBtn = this.createDiv('btn btn-primary', '保存卡牌');
            saveBtn.onclick = () => this.saveCard();
            const newBtn = this.createDiv('btn btn-success', '新建卡牌');
            newBtn.onclick = () => this.newCard();
            btnGroup.appendChild(saveBtn);
            btnGroup.appendChild(newBtn);
            container.appendChild(btnGroup);
            
            return container;
        }

        // 创建表单组
        createFormGroup(label, input) {
            const group = this.createDiv('form-group');
            const labelDiv = this.createDiv('form-label', label);
            group.appendChild(labelDiv);
            group.appendChild(input);
            return group;
        }

        // 创建自定义下拉框
        createCustomSelect(options, selected, onChange) {
            const container = this.createDiv('custom-select');
            
            const display = this.createDiv('select-display', selected || '请选择...');
            const arrow = this.createDiv('select-arrow', '▼');
            display.appendChild(arrow);
            
            const dropdown = this.createDiv('select-dropdown');
            
            options.forEach(option => {
                const optionDiv = this.createDiv('select-option', option);
                if (option === selected) {
                    optionDiv.classList.add('selected');
                }
                optionDiv.onclick = () => {
                    display.childNodes[0].textContent = option;
                    dropdown.querySelectorAll('.select-option').forEach(o => o.classList.remove('selected'));
                    optionDiv.classList.add('selected');
                    dropdown.classList.remove('active');
                    onChange(option);
                };
                dropdown.appendChild(optionDiv);
            });
            
            display.onclick = () => {
                dropdown.classList.toggle('active');
            };
            
            // 点击外部关闭
            document.addEventListener('click', (e) => {
                if (!container.contains(e.target)) {
                    dropdown.classList.remove('active');
                }
            });
            
            container.appendChild(display);
            container.appendChild(dropdown);
            
            return container;
        }

        // 创建输入框
        createInput(type, value, onChange) {
            const input = this.createDiv('custom-input');
            input.contentEditable = true;
            input.textContent = value;
            input.oninput = () => onChange(input.textContent);
            return input;
        }

        // 创建文本域
        createTextarea(value, onChange) {
            const textarea = this.createDiv('custom-textarea');
            textarea.contentEditable = true;
            textarea.innerHTML = value.replace(/<br>/g, '\n');
            textarea.oninput = () => onChange(textarea.textContent);
            return textarea;
        }

        // 创建格式化按钮
        createFormatButtons() {
            const container = this.createDiv('format-buttons');
            
            const buttons = [
                { label: '蓝色文本', class: 'blue', template: '{{文本|蓝|%s}}' },
                { label: '绿色文本', class: 'green', template: '{{文本|绿|%s}}' },
                { label: '绿色描边', class: 'green', template: '{{描边|绿|%s}}' },
                { label: '词典', class: '', template: '{{词典|%s}}' },
                { label: '换行', class: '', template: '<br>' }
            ];
            
            buttons.forEach(btn => {
                const button = this.createDiv(`format-btn ${btn.class}`, btn.label);
                button.onclick = () => {
                    const textarea = button.parentElement.nextElementSibling;
                    this.insertTemplate(textarea, btn.template);
                };
                container.appendChild(button);
            });
            
            return container;
        }

        // 插入模板
        insertTemplate(textarea, template) {
            const selection = window.getSelection();
            const selectedText = selection.toString();
            
            if (template === '<br>') {
                const text = textarea.textContent;
                const pos = this.getCaretPosition(textarea);
                textarea.textContent = text.slice(0, pos) + '\n' + text.slice(pos);
            } else {
                const result = template.replace('%s', selectedText || '选择文字');
                if (selectedText) {
                    document.execCommand('insertText', false, result);
                } else {
                    const text = textarea.textContent;
                    const pos = this.getCaretPosition(textarea);
                    textarea.textContent = text.slice(0, pos) + result + text.slice(pos);
                }
            }
            
            textarea.dispatchEvent(new Event('input'));
        }

        // 获取光标位置
        getCaretPosition(element) {
            const selection = window.getSelection();
            if (selection.rangeCount > 0) {
                const range = selection.getRangeAt(0);
                const preCaretRange = range.cloneRange();
                preCaretRange.selectNodeContents(element);
                preCaretRange.setEnd(range.endContainer, range.endOffset);
                return preCaretRange.toString().length;
            }
            return 0;
        }

        // 创建复选框
        createCheckbox(checked, onChange) {
            const container = this.createDiv('checkbox-group');
            const checkbox = this.createDiv('custom-checkbox');
            if (checked) checkbox.classList.add('checked');
            
            const label = this.createDiv('', '是');
            
            checkbox.onclick = () => {
                checkbox.classList.toggle('checked');
                const isChecked = checkbox.classList.contains('checked');
                label.textContent = isChecked ? '是' : '否';
                onChange(isChecked);
            };
            
            container.appendChild(checkbox);
            container.appendChild(label);
            return container;
        }

        // 创建卡组选择
        createGroupSelect() {
            const container = this.createDiv('group-options');
            const groups = ['自我意识技能', '起始卡牌', '独特卡牌', '灵光一闪', '神光一闪'];
            
            groups.forEach(group => {
                const option = this.createDiv('group-option', group);
                if (this.cardData.group === group) {
                    option.classList.add('selected');
                }
                option.onclick = () => {
                    container.querySelectorAll('.group-option').forEach(o => o.classList.remove('selected'));
                    option.classList.add('selected');
                    this.cardData.group = group;
                    this.updatePreview();
                };
                container.appendChild(option);
            });
            
            return container;
        }

        // 创建稀有度选择
        createRaritySelect() {
            const container = this.createDiv('rarity-options');
            const rarities = ['白', '蓝', '橙', '彩'];
            
            rarities.forEach(rarity => {
                const option = this.createDiv('rarity-option', rarity);
                if (this.cardData.rarity === rarity) {
                    option.classList.add('selected');
                }
                option.onclick = () => {
                    container.querySelectorAll('.rarity-option').forEach(o => o.classList.remove('selected'));
                    option.classList.add('selected');
                    this.cardData.rarity = rarity;
                    this.updatePreview();
                };
                container.appendChild(option);
            });
            
            return container;
        }

        // 创建神明选择
        createGodSelect() {
            const container = this.createDiv('god-options');
            const gods = ['circen', 'diallos', 'nihilum', 'secred', 'vitor'];
            
            gods.forEach(god => {
                const option = this.createDiv('god-option', god);
                if (this.cardData.god === god) {
                    option.classList.add('selected');
                }
                option.onclick = () => {
                    container.querySelectorAll('.god-option').forEach(o => o.classList.remove('selected'));
                    option.classList.add('selected');
                    this.cardData.god = god;
                    this.updatePreview();
                };
                container.appendChild(option);
            });
            
            return container;
        }

        // 创建类型选择
        createTypeSelect() {
            const container = this.createDiv('type-options');
            const types = ['攻击', '技能', '强化'];
            
            types.forEach(type => {
                const option = this.createDiv('type-option', type);
                if (this.cardData.type === type) {
                    option.classList.add('selected');
                }
                option.onclick = () => {
                    container.querySelectorAll('.type-option').forEach(o => o.classList.remove('selected'));
                    option.classList.add('selected');
                    this.cardData.type = type;
                    this.updatePreview();
                };
                container.appendChild(option);
            });
            
            return container;
        }

        // 渲染卡牌列表
        renderCardLists() {
            const container = this.createDiv();
            
            // 卡牌列表
            const cardListTitle = this.createDiv('panel-title', '卡牌列表');
            container.appendChild(cardListTitle);
            
            const cardListContainer = this.createDiv('list-container');
            cardListContainer.id = 'card-list';
            this.updateCardList(cardListContainer);
            container.appendChild(cardListContainer);
            
            return container;
        }

        // 更新卡牌列表
        updateCardList(container) {
            container.innerHTML = '';
            
            if (Object.keys(this.cards).length === 0) {
                container.appendChild(this.createDiv('list-empty', '暂无卡牌'));
                return;
            }
            
            Object.keys(this.cards).forEach(name => {
                const card = this.cards[name];
                const item = this.createDiv('card-list-item');
                
                const info = this.createDiv();
                const nameDiv = this.createDiv('card-list-item-name', name);
                const detailDiv = this.createDiv('card-list-item-info', 
                    `${card.type || '攻击'} | AP:${card.ap || 0} | ${card.rarity || ''}`
                );
                info.appendChild(nameDiv);
                info.appendChild(detailDiv);
                
                const deleteBtn = this.createDiv('delete-btn', '删除');
                deleteBtn.onclick = (e) => {
                    e.stopPropagation();
                    if (confirm(`确定要删除卡牌"${name}"吗?`)) {
                        delete this.cards[name];
                        this.updateCardList(container);
                        this.updatePreview();
                        
                        // 如果删除的是当前编辑的卡牌,清空表单
                        if (this.currentCard === name) {
                            this.newCard();
                        }
                    }
                };
                
                item.appendChild(info);
                item.appendChild(deleteBtn);
                
                item.onclick = () => {
                    this.loadCard(name);
                    container.querySelectorAll('.card-list-item').forEach(i => i.classList.remove('active'));
                    item.classList.add('active');
                };
                
                container.appendChild(item);
            });
        }

        // 渲染预览
        renderPreview() {
            const container = this.createDiv();
            const title = this.createDiv('panel-title', 'Lua代码预览');
            container.appendChild(title);
            
            const preview = this.createDiv('preview-code');
            preview.id = 'code-preview';
            container.appendChild(preview);
            
            this.updatePreview();
            
            // 添加复制按钮
            const copyBtn = this.createDiv('btn btn-primary', '复制代码');
            copyBtn.style.marginTop = '10px';
            copyBtn.onclick = () => this.copyCode();
            container.appendChild(copyBtn);
            
            return container;
        }

        // 更新预览
        updatePreview() {
            const preview = document.getElementById('code-preview');
            if (!preview) return;
            
            preview.textContent = this.generateLuaCode();
        }

        // 生成Lua代码
        generateLuaCode() {
            let code = 'local card = {}\n\n';
            
            // 生成order
            if (this.defaultData.order.length > 0) {
                code += `card.order = { "${this.defaultData.order.join(',')}" }\n\n`;
            }
            
            // 生成info
            code += 'card.info = {\n';
            if (this.defaultData.ego) {
                code += `    ego = "${this.defaultData.ego}",\n`;
            }
            code += '}\n\n';
            
            // 生成各个卡牌
            Object.keys(this.cards).forEach(name => {
                const card = this.cards[name];
                code += this.generateCardCode(name, card);
            });
            
            code += 'return card';
            
            return code;
        }

        // 生成单个卡牌代码
        generateCardCode(name, card) {
            let code = `card["${name}"] = {\n`;
            code += '    base = {\n';
            
            // 基础属性
            if (card.displayname) {
                code += `        displayname = "${card.displayname}",\n`;
            }
            if (card.art) {
                code += `        art = "${card.art}",\n`;
            }
            if (card.group) {
                code += `        group = "${card.group}",\n`;
            }
            if (card.rarity) {
                code += `        rarity = "${card.rarity}",\n`;
            }
            if (card.ap) {
                code += `        ap = ${isNaN(card.ap) ? `"${card.ap}"` : card.ap},\n`;
            }
            if (card.type) {
                code += `        type = "${card.type}",\n`;
            }
            if (card.dict) {
                code += `        dict = "${card.dict}",\n`;
            }
            if (card.desc_global) {
                const desc = card.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"');
                code += `        desc_global = "${desc}",\n`;
            }
            if (card.sub) {
                code += `        sub = "${card.sub}",\n`;
            }
            if (card.isinspiration) {
                code += `        isinspiration = 1,\n`;
            }
            if (card.isgod_inspiration) {
                code += `        isgod_inspiration = 1,\n`;
            }
            
            code += '    },\n';
            
            // 变体数据
            if (card.isinspiration || card.isgod_inspiration) {
                code += '    var = {\n';
                
                // 灵光一闪
                if (card.isinspiration && card.inspirations && card.inspirations.length > 0) {
                    code += '        inspiration = {\n';
                    card.inspirations.forEach(insp => {
                        code += '            {\n';
                        if (insp.ap !== undefined) {
                            code += `                ap = ${isNaN(insp.ap) ? `"${insp.ap}"` : insp.ap},\n`;
                        }
                        if (insp.type) {
                            code += `                type = "${insp.type}",\n`;
                        }
                        if (insp.desc_global) {
                            const desc = insp.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"');
                            code += `                desc_global = "${desc}",\n`;
                        }
                        code += '            },\n';
                    });
                    code += '        },\n';
                }
                
                // 神光一闪
                if (card.isgod_inspiration && card.god_inspirations) {
                    code += '        god_inspiration = {\n';
                    const gods = ['circen', 'diallos', 'nihilum', 'secred', 'vitor'];
                    gods.forEach(god => {
                        if (card.god_inspirations[god] && card.god_inspirations[god].length > 0) {
                            code += `            ${god} = {\n`;
                            card.god_inspirations[god].forEach(insp => {
                                code += '                {\n';
                                if (insp.ap !== undefined) {
                                    code += `                    ap = ${isNaN(insp.ap) ? `"${insp.ap}"` : insp.ap},\n`;
                                }
                                if (insp.type) {
                                    code += `                    type = "${insp.type}",\n`;
                                }
                                if (insp.desc_global) {
                                    const desc = insp.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"');
                                    code += `                    desc_global = "${desc}",\n`;
                                }
                                code += '                },\n';
                            });
                            code += '            },\n';
                        }
                    });
                    code += '        },\n';
                }
                
                code += '    },\n';
            }
            
            code += '}\n\n';
            
            return code;
        }

        // 保存卡牌
        saveCard() {
            if (!this.cardData.name) {
                alert('请输入卡牌名称!');
                return;
            }
            
            // 克隆当前卡牌数据
            const cardToSave = JSON.parse(JSON.stringify(this.cardData));
            
            // 保存到cards对象
            this.cards[cardToSave.name] = cardToSave;
            this.currentCard = cardToSave.name;
            
            // 更新order
            if (!this.defaultData.order.includes(cardToSave.name)) {
                this.defaultData.order.push(cardToSave.name);
            }
            
            // 更新列表和预览
            const listContainer = document.getElementById('card-list');
            if (listContainer) {
                this.updateCardList(listContainer);
            }
            this.updatePreview();
            
            alert('卡牌保存成功!');
        }

        // 新建卡牌
        newCard() {
            this.currentCard = null;
            this.cardData = {
                name: '',
                displayname: '',
                art: '',
                group: '',
                rarity: '',
                god: '',
                ap: '',
                type: '攻击',
                dict: '',
                desc_global: '',
                sub: '',
                isinspiration: false,
                isgod_inspiration: false,
                inspirations: [],
                god_inspirations: {
                    circen: [],
                    diallos: [],
                    nihilum: [],
                    secred: [],
                    vitor: []
                }
            };
            
            // 重新渲染输入区
            const leftPanel = document.querySelector('.card-input-panel');
            if (leftPanel) {
                leftPanel.innerHTML = '';
                leftPanel.appendChild(this.renderFighterSelect());
                leftPanel.appendChild(this.renderDefaultInfo());
                leftPanel.appendChild(this.renderCardInput());
            }
            
            // 清除列表选中状态
            const listContainer = document.getElementById('card-list');
            if (listContainer) {
                listContainer.querySelectorAll('.card-list-item').forEach(i => i.classList.remove('active'));
            }
        }

        // 加载卡牌
        loadCard(name) {
            if (!this.cards[name]) return;
            
            this.currentCard = name;
            this.cardData = JSON.parse(JSON.stringify(this.cards[name]));
            
            // 重新渲染输入区
            const leftPanel = document.querySelector('.card-input-panel');
            if (leftPanel) {
                leftPanel.innerHTML = '';
                leftPanel.appendChild(this.renderFighterSelect());
                leftPanel.appendChild(this.renderDefaultInfo());
                leftPanel.appendChild(this.renderCardInput());
            }
        }

        // 加载战斗员数据
        async loadFighterData() {
            if (!this.currentFighter) return;
            
            try {
                const api = new mw.Api();
                const moduleName = `模块:卡牌/${this.currentFighter}`;
                
                const response = await api.get({
                    action: 'query',
                    prop: 'revisions',
                    titles: moduleName,
                    rvprop: 'content',
                    rvslots: 'main'
                });
                
                const pages = response.query.pages;
                const page = Object.values(pages)[0];
                
                if (page.revisions) {
                    const content = page.revisions[0].slots.main['*'];
                    this.parseLuaCode(content);
                    
                    // 重新渲染
                    this.render();
                }
            } catch (error) {
                console.error('加载战斗员数据失败:', error);
            }
        }

        // 解析Lua代码(简化版)
        parseLuaCode(code) {
            // 这里应该实现完整的Lua代码解析
            // 由于复杂度较高,这里只做基本的解析示例
            
            // 解析order
            const orderMatch = code.match(/card\.order\s*=\s*{\s*"([^"]*)"\s*}/);
            if (orderMatch) {
                this.defaultData.order = orderMatch[1].split(',').map(s => s.trim());
            }
            
            // 解析ego
            const egoMatch = code.match(/ego\s*=\s*"([^"]*)"/);
            if (egoMatch) {
                this.defaultData.ego = egoMatch[1];
            }
            
            // 这里应该继续解析各个卡牌的数据
            // 由于Lua语法复杂,建议使用专门的Lua解析器
        }

        // 保存到Mediawiki
        async saveToMediawiki() {
            if (!this.currentFighter) {
                alert('请先选择战斗员!');
                return;
            }
            
            const code = this.generateLuaCode();
            const moduleName = `模块:卡牌/${this.currentFighter}`;
            
            try {
                const api = new mw.Api();
                await api.postWithToken('csrf', {
                    action: 'edit',
                    title: moduleName,
                    text: code,
                    summary: '通过卡牌管理器更新',
                    contentmodel: 'Scribunto'
                });
                
                alert('保存成功!');
            } catch (error) {
                console.error('保存失败:', error);
                alert('保存失败:' + error);
            }
        }

        // 复制代码
        copyCode() {
            const code = this.generateLuaCode();
            
            // 创建临时文本域
            const textarea = document.createElement('textarea');
            textarea.value = code;
            textarea.style.position = 'fixed';
            textarea.style.opacity = '0';
            document.body.appendChild(textarea);
            
            textarea.select();
            document.execCommand('copy');
            document.body.removeChild(textarea);
            
            alert('代码已复制到剪贴板!');
        }

        // 绑定事件
        bindEvents() {
            // 可以在这里添加全局事件监听
        }
    }

    // 等待页面加载完成
    if (mw.config.get('wgPageName') === 'Special:Card' || 
        window.location.search.includes('cardmanager=1')) {
        mw.loader.using(['mediawiki.api']).then(() => {
            const manager = new CardManager();
            manager.init();
        });
    }

    // 添加导航链接(可选)
    mw.loader.using(['mediawiki.util']).then(() => {
        mw.util.addPortletLink(
            'p-tb',
            '?cardmanager=1',
            '卡牌管理器',
            't-cardmanager',
            '打开卡牌管理器'
        );
    });

})();