MediaWiki

MediaWiki:Card.js

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献2025年10月23日 (四) 15:58的版本

注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
// MediaWiki:Card.js
(function() {
    'use strict';
    
    // 加载CSS
    mw.loader.load('/index.php?title=Template:Card.css&action=raw&ctype=text/css', 'text/css');
    
    // 主管理器对象
    const CardManager = {
        currentFighter: '',
        cardData: {},
        cardList: [],
        
        init: function() {
            this.createInterface();
            this.loadFighters();
            this.bindEvents();
        },
        
        createInterface: function() {
            const container = $('<div>').attr('id', 'card-manager').addClass('card-manager-container');
            
            // 创建三列布局
            const leftPanel = this.createLeftPanel();
            const centerPanel = this.createCenterPanel();
            const rightPanel = this.createRightPanel();
            
            container.append(leftPanel, centerPanel, rightPanel);
            $('#mw-content-text').prepend(container);
        },
        
        createLeftPanel: function() {
            const panel = $('<div>').addClass('card-panel card-panel-left');
            
            // 战斗员选择
            const fighterSection = $('<div>').addClass('card-section');
            fighterSection.append(
                $('<div>').addClass('section-title').text('战斗员选择'),
                $('<div>').addClass('form-group').append(
                    $('<div>').addClass('form-label').text('当前战斗员:'),
                    $('<div>').attr('id', 'fighter-select').addClass('custom-select').append(
                        $('<div>').addClass('select-display').text('请选择战斗员'),
                        $('<div>').addClass('select-options').hide()
                    )
                )
            );
            
            // 默认信息区
            const defaultInfo = $('<div>').addClass('card-section');
            defaultInfo.append(
                $('<div>').addClass('section-title').text('默认信息'),
                this.createInput('card-order', '卡牌顺序', '灭,灭,救,虚无残影,消灭烙印,黑洞,虚妄的誓约,无忧的回声'),
                this.createInput('ego', '属性', '虚无')
            );
            
            // 卡牌数据输入区
            const cardDataSection = $('<div>').addClass('card-section');
            cardDataSection.append(
                $('<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;
        },
        
        createCenterPanel: function() {
            const panel = $('<div>').addClass('card-panel card-panel-center');
            
            // 卡牌列表
            const cardListSection = $('<div>').addClass('card-section');
            cardListSection.append(
                $('<div>').addClass('section-title').text('卡牌列表'),
                $('<div>').attr('id', 'card-list').addClass('card-list')
            );
            
            // 灵光一闪列表
            const inspirationSection = $('<div>').addClass('card-section');
            inspirationSection.append(
                $('<div>').addClass('section-title').text('灵光一闪列表'),
                $('<div>').attr('id', 'inspiration-list').addClass('card-list')
            );
            
            // 神光一闪列表
            const godInspirationSection = $('<div>').addClass('card-section');
            godInspirationSection.append(
                $('<div>').addClass('section-title').text('神光一闪列表'),
                $('<div>').attr('id', 'god-inspiration-list').addClass('card-list')
            );
            
            // 操作按钮
            const buttonSection = $('<div>').addClass('card-section button-group');
            buttonSection.append(
                $('<div>').addClass('card-button button-add').text('添加卡牌'),
                $('<div>').addClass('card-button button-update').text('更新卡牌'),
                $('<div>').addClass('card-button button-delete').text('删除卡牌'),
                $('<div>').addClass('card-button button-save').text('保存到模块')
            );
            
            panel.append(cardListSection, inspirationSection, godInspirationSection, buttonSection);
            return panel;
        },
        
        createRightPanel: function() {
            const panel = $('<div>').addClass('card-panel card-panel-right');
            
            const previewSection = $('<div>').addClass('card-section');
            previewSection.append(
                $('<div>').addClass('section-title').text('Lua代码预览'),
                $('<div>').addClass('code-preview-wrapper').append(
                    $('<pre>').attr('id', 'lua-preview').addClass('lua-preview')
                )
            );
            
            panel.append(previewSection);
            return panel;
        },
        
        createInput: function(id, label, placeholder) {
            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 => {
                optionsContainer.append(
                    $('<div>').addClass('select-option').text(opt)
                );
            });
            
            return dropdown;
        },
        
        createCheckbox: function(id, label) {
            return $('<div>').addClass('form-group').append(
                $('<div>').addClass('form-label').text(label + ':'),
                $('<div>').attr('id', id).addClass('custom-checkbox').append(
                    $('<div>').addClass('checkbox-box'),
                    $('<div>').addClass('checkbox-label').text('否')
                ).data('checked', false)
            );
        },
        
        createDescriptionInput: function() {
            const descGroup = $('<div>').addClass('form-group');
            
            // 工具栏
            const toolbar = $('<div>').addClass('desc-toolbar').append(
                $('<div>').addClass('toolbar-btn').text('蓝色文本').data('format', 'blue'),
                $('<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(
                $('<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;
        },
        
        loadFighters: function() {
            // 通过API加载战斗员分类的页面
            new mw.Api().get({
                action: 'query',
                list: 'categorymembers',
                cmtitle: 'Category:战斗员',
                cmlimit: 500,
                format: 'json'
            }).done(function(data) {
                const fighterSelect = $('#fighter-select .select-options');
                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;
            
            // 下拉框事件
            $(document).on('click', '.custom-select', function(e) {
                e.stopPropagation();
                const options = $(this).find('.select-options');
                $('.select-options').not(options).hide();
                options.toggle();
            });
            
            $(document).on('click', '.select-option', function(e) {
                e.stopPropagation();
                const select = $(this).closest('.custom-select');
                const display = select.find('.select-display');
                display.text($(this).text());
                $(this).parent().hide();
                
                if (select.attr('id') === 'fighter-select') {
                    self.currentFighter = $(this).data('fighter');
                    self.loadFighterCards();
                }
            });
            
            // 复选框事件
            $(document).on('click', '.custom-checkbox', function() {
                const isChecked = !$(this).data('checked');
                $(this).data('checked', isChecked);
                $(this).find('.checkbox-box').toggleClass('checked');
                $(this).find('.checkbox-label').text(isChecked ? '是' : '否');
            });
            
            // 描述工具栏事件
            $(document).on('click', '.toolbar-btn', function() {
                const format = $(this).data('format');
                const textarea = $('#desc_global')[0];
                const selection = window.getSelection();
                const selectedText = selection.toString();
                
                let insertText = '';
                switch(format) {
                    case 'blue':
                        insertText = selectedText ? `{{文本|蓝|${selectedText}}}` : '{{文本|蓝|}}';
                        break;
                    case 'green':
                        insertText = selectedText ? `{{文本|绿|${selectedText}}}` : '{{文本|绿|}}';
                        break;
                    case 'outline':
                        insertText = selectedText ? `{{描边|绿|${selectedText}}}` : '{{描边|绿|}}';
                        break;
                    case 'dict':
                        insertText = selectedText ? `{{词典|${selectedText}}}` : '{{词典|}}';
                        break;
                    case 'br':
                        insertText = '<br>';
                        break;
                }
                
                document.execCommand('insertHTML', false, insertText);
            });
            
            // 按钮事件
            $('.button-add').on('click', function() {
                self.addCard();
            });
            
            $('.button-update').on('click', function() {
                self.updateCard();
            });
            
            $('.button-delete').on('click', function() {
                self.deleteCard();
            });
            
            $('.button-save').on('click', function() {
                self.saveToModule();
            });
            
            // 输入变化时更新预览
            $(document).on('input', '.custom-input, .custom-textarea', function() {
                self.updatePreview();
            });
            
            // 点击其他地方关闭下拉框
            $(document).on('click', function() {
                $('.select-options').hide();
            });
        },
        
        addCard: function() {
            const cardName = $('#card-name').text();
            if (!cardName) {
                mw.notify('请输入卡牌名称', {type: 'error'});
                return;
            }
            
            const cardData = this.getFormData();
            this.cardData[cardName] = cardData;
            this.updateCardList();
            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;
            this.updateCardList();
            this.updatePreview();
            mw.notify('卡牌更新成功', {type: 'success'});
        },
        
        deleteCard: function() {
            const cardName = $('#card-name').text();
            if (!cardName || !this.cardData[cardName]) {
                mw.notify('请选择要删除的卡牌', {type: 'error'});
                return;
            }
            
            delete this.cardData[cardName];
            this.updateCardList();
            this.updatePreview();
            this.clearForm();
            mw.notify('卡牌删除成功', {type: 'success'});
        },
        
        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: {}
            };
            
            // 如果有灵光一闪,添加默认数据
            if (data.base.isinspiration) {
                data.var.inspiration = [
                    { 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 }
                ];
            }
            
            // 如果有神光一闪,添加默认数据
            if (data.base.god_inspiration) {
                data.var.god_inspiration = {
                    circen: [{ ap: 1 }],
                    diallos: [{ ap: 1 }],
                    nihilum: [{ ap: 1 }],
                    secred: [{ ap: 1 }],
                    vitor: [{ ap: 1 }]
                };
            }
            
            return data;
        },
        
        updateCardList: function() {
            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);
            $('#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;
            $('#isinspiration').data('checked', inspirationChecked);
            $('#isinspiration .checkbox-box').toggleClass('checked', inspirationChecked);
            $('#isinspiration .checkbox-label').text(inspirationChecked ? '是' : '否');
            
            const godChecked = card.base.god_inspiration === 1;
            $('#god_inspiration').data('checked', godChecked);
            $('#god_inspiration .checkbox-box').toggleClass('checked', godChecked);
            $('#god_inspiration .checkbox-label').text(godChecked ? '是' : '否');
        },
        
        clearForm: function() {
            $('.custom-input').text('');
            $('.custom-textarea').html('');
            $('.custom-checkbox').data('checked', false);
            $('.checkbox-box').removeClass('checked');
            $('.checkbox-label').text('否');
        },
        
        updatePreview: function() {
            const cardOrder = $('#card-order').text();
            const ego = $('#ego').text();
            
            let luaCode = 'local card = {}\n\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];
                luaCode += `card["${cardName}"] = {\n`;
                luaCode += '    base = {\n';
                
                Object.keys(card.base).forEach(key => {
                    const value = card.base[key];
                    if (value !== '' && value !== 0) {
                        if (typeof value === 'number') {
                            luaCode += `        ${key} = ${value},\n`;
                        } else {
                            luaCode += `        ${key} = "${value}",\n`;
                        }
                    }
                });
                
                luaCode += '    },\n';
                
                if (card.var && Object.keys(card.var).length > 0) {
                    luaCode += '    var = {\n';
                    
                    if (card.var.inspiration) {
                        luaCode += '        inspiration = {\n';
                        card.var.inspiration.forEach(insp => {
                            luaCode += '            {\n';
                            Object.keys(insp).forEach(key => {
                                if (typeof insp[key] === 'number') {
                                    luaCode += `                ${key} = ${insp[key]},\n`;
                                } else {
                                    luaCode += `                ${key} = "${insp[key]}",\n`;
                                }
                            });
                            luaCode += '            },\n';
                        });
                        luaCode += '        },\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';
            });
            
            luaCode += 'return card';
            
            $('#lua-preview').text(luaCode);
        },
        
        loadFighterCards: function() {
            if (!this.currentFighter) return;
            
            const moduleName = `模块:卡牌/${this.currentFighter}`;
            
            new mw.Api().get({
                action: 'query',
                prop: 'revisions',
                titles: moduleName,
                rvprop: 'content',
                format: 'json'
            }).done((data) => {
                const pages = data.query.pages;
                const pageId = Object.keys(pages)[0];
                
                if (pageId !== '-1') {
                    const content = pages[pageId].revisions[0]['*'];
                    // 这里需要解析Lua内容并加载到界面
                    this.parseLuaContent(content);
                }
            });
        },
        
        parseLuaContent: function(content) {
            // 简化的Lua解析,实际使用可能需要更复杂的解析器
            try {
                // 提取卡牌数据
                const cardMatches = content.matchAll(/card\["([^"]+)"\]\s*=\s*{([^}]+})}/gs);
                
                this.cardData = {};
                for (const match of cardMatches) {
                    const cardName = match[1];
                    // 这里需要更复杂的解析逻辑
                    // 暂时使用简化版本
                }
                
                this.updateCardList();
                this.updatePreview();
            } catch (e) {
                console.error('解析Lua内容失败:', e);
            }
        },
        
        saveToModule: function() {
            if (!this.currentFighter) {
                mw.notify('请先选择战斗员', {type: 'error'});
                return;
            }
            
            const moduleName = `模块:卡牌/${this.currentFighter}`;
            const luaContent = $('#lua-preview').text();
            
            new mw.Api().postWithToken('csrf', {
                action: 'edit',
                title: moduleName,
                text: luaContent,
                summary: '更新卡牌数据',
                format: 'json'
            }).done(function() {
                mw.notify('保存成功!', {type: 'success'});
            }).fail(function(error) {
                mw.notify('保存失败:' + error, {type: 'error'});
            });
        }
    };
    
    // 页面加载完成后初始化
    $(document).ready(function() {
        // 只在特定页面加载
        if (mw.config.get('wgPageName') === 'Special:CardManager' || 
            mw.config.get('wgPageName').indexOf('卡牌管理') !== -1) {
            CardManager.init();
        }
    });
    
    // 添加到全局对象以便调试
    window.CardManager = CardManager;
})();