MediaWiki

MediaWiki:Card.js

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献2025年10月2日 (四) 10:43的版本

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

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
window.CardEditor = {
    cards: [],
    currentCard: null,
    currentVariantIndex: null,
    api: new mw.Api(),

    init: function() {
        this.createUI();
        this.bindEvents();
        this.loadAllCards();
    },

    createUI: function() {
        var html = 
        '<div id="card-editor">' +
            '<div class="ce-container">' +
                // 左侧输入区
                '<div class="ce-left">' +
                    '<div class="ce-group">' +
                        '<div class="ce-group-title">卡牌数据</div>' +
                        '<div class="ce-form">' +
                            // 名称
                            '<div class="ce-row">' +
                                '<div class="ce-label">卡牌名称:</div>' +
                                '<input type="text" id="ce-name" class="ce-input" placeholder="请输入卡牌名称...">' +
                            '</div>' +
                            // 卡组
                            '<div class="ce-row">' +
                                '<div class="ce-label">卡组类型:</div>' +
                                '<div class="ce-select-wrapper">' +
                                    '<input type="text" id="ce-deck" class="ce-select-input" placeholder="点击选择或输入..." readonly>' +
                                    '<div class="ce-select-dropdown" id="ce-deck-dropdown">' +
                                        '<div class="ce-select-option" data-value="">请选择</div>' +
                                        '<div class="ce-select-option" data-value="起始卡牌">起始卡牌</div>' +
                                        '<div class="ce-select-option" data-value="独特卡牌">独特卡牌</div>' +
                                        '<div class="ce-select-option" data-value="灵光一闪">灵光一闪</div>' +
                                        '<div class="ce-select-option" data-value="衍生卡牌">衍生卡牌</div>' +
                                    '</div>' +
                                '</div>' +
                            '</div>' +
                            // 图片
                            '<div class="ce-row">' +
                                '<div class="ce-label">图片文件:</div>' +
                                '<input type="text" id="ce-art" class="ce-input" placeholder="输入图片文件名...">' +
                            '</div>' +
                            // 属性
                            '<div class="ce-row">' +
                                '<div class="ce-label">属性:</div>' +
                                '<div class="ce-select-wrapper">' +
                                    '<input type="text" id="ce-attr" class="ce-select-input" placeholder="点击选择..." readonly>' +
                                    '<div class="ce-select-dropdown" id="ce-attr-dropdown">' +
                                        '<div class="ce-select-option" data-value="">请选择</div>' +
                                        '<div class="ce-select-option" data-value="热情">热情</div>' +
                                        '<div class="ce-select-option" data-value="秩序">秩序</div>' +
                                        '<div class="ce-select-option" data-value="正义">正义</div>' +
                                        '<div class="ce-select-option" data-value="本能">本能</div>' +
                                        '<div class="ce-select-option" data-value="虚无">虚无</div>' +
                                    '</div>' +
                                '</div>' +
                            '</div>' +
                            // 稀有度
                            '<div class="ce-row">' +
                                '<div class="ce-label">稀有度:</div>' +
                                '<div class="ce-select-wrapper">' +
                                    '<input type="text" id="ce-rarity" class="ce-select-input" placeholder="点击选择..." readonly>' +
                                    '<div class="ce-select-dropdown" id="ce-rarity-dropdown">' +
                                        '<div class="ce-select-option" data-value="">请选择</div>' +
                                        '<div class="ce-select-option" data-value="白">白</div>' +
                                        '<div class="ce-select-option" data-value="蓝">蓝</div>' +
                                        '<div class="ce-select-option" data-value="橙">橙</div>' +
                                        '<div class="ce-select-option" data-value="彩">彩</div>' +
                                    '</div>' +
                                '</div>' +
                            '</div>' +
                            // AP
                            '<div class="ce-row">' +
                                '<div class="ce-label">AP (行动点):</div>' +
                                '<input type="text" id="ce-ap" class="ce-input" placeholder="输入AP数值...">' +
                            '</div>' +
                            // 类型
                            '<div class="ce-row">' +
                                '<div class="ce-label">卡牌类型:</div>' +
                                '<div class="ce-select-wrapper">' +
                                    '<input type="text" id="ce-type" class="ce-select-input" placeholder="点击选择..." readonly>' +
                                    '<div class="ce-select-dropdown" id="ce-type-dropdown">' +
                                        '<div class="ce-select-option" data-value="">请选择</div>' +
                                        '<div class="ce-select-option" data-value="攻击">攻击</div>' +
                                        '<div class="ce-select-option" data-value="技能">技能</div>' +
                                        '<div class="ce-select-option" data-value="强化">强化</div>' +
                                        '<div class="ce-select-option" data-value="状态异常">状态异常</div>' +
                                    '</div>' +
                                '</div>' +
                            '</div>' +
                            // 机制
                            '<div class="ce-row">' +
                                '<div class="ce-label">卡牌机制:</div>' +
                                '<input type="text" id="ce-mechanism" class="ce-input" placeholder="请输入卡牌机制...">' +
                            '</div>' +
                            // 描述
                            '<div class="ce-row">' +
                                '<div class="ce-label">卡牌描述:</div>' +
                                '<div class="ce-desc-wrapper">' +
                                    '<div class="ce-format-buttons">' +
                                        '<div class="ce-btn ce-btn-small ce-btn-blue" id="ce-blue-text">蓝色文本</div>' +
                                        '<div class="ce-btn ce-btn-small ce-btn-green" id="ce-green-text">绿色文本</div>' +
                                        '<div class="ce-btn ce-btn-small ce-btn-lime" id="ce-green-stroke">绿色描边</div>' +
                                        '<div class="ce-btn ce-btn-small ce-btn-orange" id="ce-insert-br">插入换行</div>' +
                                    '</div>' +
                                    '<textarea id="ce-desc" class="ce-textarea" placeholder="请输入卡牌描述..."></textarea>' +
                                '</div>' +
                            '</div>' +
                            // 衍生卡牌
                            '<div class="ce-row">' +
                                '<div class="ce-label">衍生卡牌:</div>' +
                                '<input type="text" id="ce-derived" class="ce-input" placeholder="请输入衍生卡牌...">' +
                            '</div>' +
                        '</div>' +
                    '</div>' +
                    // 按钮区
                    '<div class="ce-buttons">' +
                        '<div class="ce-btn ce-btn-primary" id="ce-add-card">添加卡牌</div>' +
                        '<div class="ce-btn ce-btn-primary" id="ce-add-variant">添加变体</div>' +
                        '<div class="ce-btn" id="ce-save-data">保存数据</div>' +
                        '<div class="ce-btn" id="ce-clear-form">清空表单</div>' +
                    '</div>' +
                '</div>' +
                // 中间列表区
                '<div class="ce-middle">' +
                    '<div class="ce-group">' +
                        '<div class="ce-group-title">卡牌列表</div>' +
                        '<div class="ce-list-container">' +
                            '<div id="ce-card-list" class="ce-list"></div>' +
                        '</div>' +
                    '</div>' +
                    '<div class="ce-group">' +
                        '<div class="ce-group-title">变体列表</div>' +
                        '<div class="ce-list-container">' +
                            '<div id="ce-variant-list" class="ce-list"></div>' +
                        '</div>' +
                    '</div>' +
                    '<div class="ce-buttons">' +
                        '<div class="ce-btn ce-btn-danger" id="ce-delete-card">删除卡牌</div>' +
                        '<div class="ce-btn ce-btn-danger" id="ce-delete-variant">删除变体</div>' +
                    '</div>' +
                '</div>' +
                // 右侧代码区
                '<div class="ce-right">' +
                    '<div class="ce-group">' +
                        '<div class="ce-group-title">Lua代码预览</div>' +
                        '<textarea id="ce-code-display" class="ce-code" readonly></textarea>' +
                    '</div>' +
                    '<div class="ce-buttons">' +
                        '<div class="ce-btn" id="ce-load-cards">加载卡牌数据</div>' +
                        '<div class="ce-btn" id="ce-save-to-wiki">保存到Wiki</div>' +
                        '<div class="ce-btn" id="ce-copy-code">复制代码</div>' +
                    '</div>' +
                '</div>' +
            '</div>' +
        '</div>';

        $('#mw-content-text').html(html);
    },

    bindEvents: function() {
        var self = this;

        // 自定义下拉框点击事件
        $('.ce-select-input').on('click', function() {
            var dropdown = $(this).siblings('.ce-select-dropdown');
            $('.ce-select-dropdown').not(dropdown).hide();
            dropdown.toggle();
        });

        $('.ce-select-option').on('click', function() {
            var value = $(this).data('value');
            var text = $(this).text();
            var input = $(this).parent().siblings('.ce-select-input');
            input.val(value || '');
            input.data('value', value);
            $(this).parent().hide();
        });

        // 点击其他地方关闭下拉框
        $(document).on('click', function(e) {
            if (!$(e.target).closest('.ce-select-wrapper').length) {
                $('.ce-select-dropdown').hide();
            }
        });

        // 按钮事件
        $('#ce-add-card').on('click', function() { self.addCard(); });
        $('#ce-add-variant').on('click', function() { self.addVariant(); });
        $('#ce-save-data').on('click', function() { self.saveData(); });
        $('#ce-clear-form').on('click', function() { self.clearForm(); });
        $('#ce-delete-card').on('click', function() { self.deleteCard(); });
        $('#ce-delete-variant').on('click', function() { self.deleteVariant(); });
        $('#ce-load-cards').on('click', function() { self.loadAllCards(); });
        $('#ce-save-to-wiki').on('click', function() { self.saveToWiki(); });
        $('#ce-copy-code').on('click', function() { self.copyCode(); });

        // 文本格式化按钮
        $('#ce-blue-text').on('click', function() { self.insertTextFormat('蓝'); });
        $('#ce-green-text').on('click', function() { self.insertTextFormat('绿'); });
        $('#ce-green-stroke').on('click', function() { self.insertStrokeFormat(); });
        $('#ce-insert-br').on('click', function() { self.insertBr(); });

        // 列表项点击事件
        $(document).on('click', '.ce-list-item', function() {
            var $this = $(this);
            var listId = $this.parent().attr('id');
            
            $('.ce-list-item').removeClass('selected');
            $this.addClass('selected');

            if (listId === 'ce-card-list') {
                var index = $this.data('index');
                self.onCardSelected(index);
            } else if (listId === 'ce-variant-list') {
                var index = $this.data('index');
                self.onVariantSelected(index);
            }
        });
    },

    getCardData: function() {
        var variant = {};
        
        var art = $('#ce-art').val().trim();
        if (art) variant.art = art;
        
        var deck = $('#ce-deck').val().trim();
        if (deck) variant['卡组'] = deck;
        
        var attr = $('#ce-attr').val().trim();
        if (attr) variant['属性'] = attr;
        
        var rarity = $('#ce-rarity').val().trim();
        if (rarity) variant['稀有度'] = rarity;
        
        var ap = $('#ce-ap').val().trim();
        if (ap) {
            if (ap.toUpperCase() === 'X') {
                variant.AP = 'X';
            } else if (/^\d+$/.test(ap)) {
                variant.AP = parseInt(ap);
            } else {
                variant.AP = ap;
            }
        }
        
        var mechanism = $('#ce-mechanism').val().trim();
        if (mechanism) variant['机制'] = mechanism;
        
        var type = $('#ce-type').val().trim();
        if (type) variant['类型'] = type;
        
        var desc = $('#ce-desc').val().trim();
        if (desc) variant['描述'] = desc;
        
        var derived = $('#ce-derived').val().trim();
        if (derived) variant['衍生卡牌'] = derived;

        return {
            name: $('#ce-name').val().trim(),
            variants: [variant]
        };
    },

    setCardData: function(card, variantIndex) {
        variantIndex = variantIndex || 0;
        
        $('#ce-name').val(card.name);
        
        if (variantIndex < card.variants.length) {
            var isVariant = variant['卡组'] === '灵光一闪';
            
            // 设置字段是否可编辑
            $('#ce-name').prop('disabled', isVariant);
            $('#ce-art').prop('disabled', isVariant);
            $('#ce-attr').prop('disabled', isVariant);
            $('#ce-rarity').prop('disabled', isVariant);
            $('#ce-derived').prop('disabled', isVariant);
            
            // 设置值
            $('#ce-art').val(variant.art || '');
            $('#ce-deck').val(variant['卡组'] || '');
            $('#ce-attr').val(variant['属性'] || '');
            $('#ce-rarity').val(variant['稀有度'] || '');
            
            var ap = variant.AP;
            $('#ce-ap').val(ap !== undefined ? String(ap) : '');
            
            $('#ce-mechanism').val(variant['机制'] || '');
            $('#ce-type').val(variant['类型'] || '');
            $('#ce-desc').val(variant['描述'] || '');
            $('#ce-derived').val(variant['衍生卡牌'] || '');
        }
    },

    clearForm: function() {
        $('#ce-name').val('').prop('disabled', false);
        $('#ce-art').val('').prop('disabled', false);
        $('#ce-deck').val('');
        $('#ce-attr').val('').prop('disabled', false);
        $('#ce-rarity').val('').prop('disabled', false);
        $('#ce-ap').val('');
        $('#ce-mechanism').val('');
        $('#ce-type').val('');
        $('#ce-desc').val('');
        $('#ce-derived').val('').prop('disabled', false);
    },

    addCard: function() {
        var cardData = this.getCardData();
        if (!cardData.name) {
            alert('卡牌名称不能为空!');
            return;
        }
        
        this.cards.push(cardData);
        this.currentCard = cardData;
        this.currentVariantIndex = 0;
        this.updateCardList();
        this.updateVariantList();
        this.updateCode();
        this.clearForm();
        alert('卡牌 "' + cardData.name + '" 添加成功!');
    },

    addVariant: function() {
        if (!this.currentCard) {
            alert('请先选择一个卡牌!');
            return;
        }
        
        var variantData = this.getCardData();
        var variant = variantData.variants[0];
        variant['卡组'] = '灵光一闪';
        
        this.currentCard.variants.push(variant);
        this.currentVariantIndex = this.currentCard.variants.length - 1;
        this.updateVariantList();
        this.updateCode();
        alert('为 "' + this.currentCard.name + '" 添加变体成功!');
    },

    saveData: function() {
        if (!this.currentCard || this.currentVariantIndex === null) {
            alert('请先选择要保存的卡牌或变体!');
            return;
        }
        
        var cardData = this.getCardData();
        var isVariant = this.currentVariantIndex > 0;
        
        if (isVariant) {
            var variant = cardData.variants[0];
            variant['卡组'] = '灵光一闪';
            this.currentCard.variants[this.currentVariantIndex] = variant;
        } else {
            this.currentCard.name = cardData.name;
            this.currentCard.variants[0] = cardData.variants[0];
        }
        
        this.updateCardList();
        this.updateVariantList();
        this.updateCode();
        alert('数据保存成功!');
    },

    deleteCard: function() {
        if (!this.currentCard) {
            alert('请先选择要删除的卡牌!');
            return;
        }
        
        if (confirm('确定要删除卡牌 "' + this.currentCard.name + '" 吗?')) {
            var index = this.cards.indexOf(this.currentCard);
            this.cards.splice(index, 1);
            this.currentCard = null;
            this.currentVariantIndex = null;
            this.updateCardList();
            this.updateVariantList();
            this.updateCode();
            this.clearForm();
            alert('卡牌删除成功!');
        }
    },

    deleteVariant: function() {
        if (!this.currentCard || this.currentVariantIndex === null) {
            alert('请先选择要删除的变体!');
            return;
        }
        
        if (this.currentVariantIndex === 0) {
            alert('不能删除主卡牌变体!');
            return;
        }
        
        if (confirm('确定要删除这个变体吗?')) {
            this.currentCard.variants.splice(this.currentVariantIndex, 1);
            this.currentVariantIndex = 0;
            this.updateVariantList();
            this.updateCode();
            this.setCardData(this.currentCard, 0);
            alert('变体删除成功!');
        }
    },

    onCardSelected: function(index) {
        this.currentCard = this.cards[index];
        this.currentVariantIndex = 0;
        this.updateVariantList();
        this.setCardData(this.currentCard, 0);
    },

    onVariantSelected: function(index) {
        if (!this.currentCard) return;
        this.currentVariantIndex = index;
        this.setCardData(this.currentCard, index);
    },

    updateCardList: function() {
        var html = '';
        for (var i = 0; i < this.cards.length; i++) {
            html += '<div class="ce-list-item" data-index="' + i + '">' + 
                    this.cards[i].name + '</div>';
        }
        $('#ce-card-list').html(html);
    },

    updateVariantList: function() {
        var html = '';
        if (this.currentCard) {
            for (var i = 0; i < this.currentCard.variants.length; i++) {
                var variant = this.currentCard.variants[i];
                var deck = variant['卡组'] || '未知';
                var name = i === 0 ? '主卡牌 (' + deck + ')' : '变体 ' + i + ' (灵光一闪)';
                html += '<div class="ce-list-item" data-index="' + i + '">' + name + '</div>';
            }
        }
        $('#ce-variant-list').html(html);
    },

    insertTextFormat: function(color) {
        var textarea = document.getElementById('ce-desc');
        var start = textarea.selectionStart;
        var end = textarea.selectionEnd;
        var text = textarea.value;
        var selectedText = text.substring(start, end);
        
        var newText = '{{文本|' + color + '|' + selectedText + '}}';
        textarea.value = text.substring(0, start) + newText + text.substring(end);
        
        // 设置光标位置
        var cursorPos = start + newText.length;
        textarea.setSelectionRange(cursorPos, cursorPos);
        textarea.focus();
    },

    insertStrokeFormat: function() {
        var textarea = document.getElementById('ce-desc');
        var start = textarea.selectionStart;
        var end = textarea.selectionEnd;
        var text = textarea.value;
        var selectedText = text.substring(start, end);
        
        var newText = '{{描边|绿|' + selectedText + '}}';
        textarea.value = text.substring(0, start) + newText + text.substring(end);
        
        var cursorPos = start + newText.length;
        textarea.setSelectionRange(cursorPos, cursorPos);
        textarea.focus();
    },

    insertBr: function() {
        var textarea = document.getElementById('ce-desc');
        var start = textarea.selectionStart;
        var text = textarea.value;
        
        textarea.value = text.substring(0, start) + '<br>' + text.substring(start);
        
        var cursorPos = start + 4;
        textarea.setSelectionRange(cursorPos, cursorPos);
        textarea.focus();
    },

    escapeLuaString: function(s) {
        if (typeof s !== 'string') return s;
        return s.replace(/\\/g, '\\\\')
               .replace(/"/g, '\\"')
               .replace(/\n/g, '\\n');
    },

    generateLuaCode: function() {
        if (this.cards.length === 0) return '-- 暂无数据';
        
        var lua = 'local p = {}\n\n';
        
        // 生成 cardOrder
        lua += 'local cardOrder = {\n';
        for (var i = 0; i < this.cards.length; i++) {
            var card = this.cards[i];
            if (card.variants.length > 0 && card.variants[0]['卡组'] !== '衍生卡牌') {
                lua += '    "' + this.escapeLuaString(card.name) + '",\n';
            }
        }
        lua += '}\n\n';
        
        // 生成 card 数据
        lua += 'local card = {\n';
        for (var i = 0; i < this.cards.length; i++) {
            var card = this.cards[i];
            lua += '    ["' + this.escapeLuaString(card.name) + '"] = {\n';
            
            for (var j = 0; j < card.variants.length; j++) {
                var variant = card.variants[j];
                lua += '        {\n';
                
                var fieldOrder = ['art', '卡组', '属性', '稀有度', 'AP', '机制', '类型', '描述', '衍生卡牌'];
                for (var k = 0; k < fieldOrder.length; k++) {
                    var field = fieldOrder[k];
                    if (variant[field] !== undefined && variant[field] !== null) {
                        var value = variant[field];
                        if (typeof value === 'string' && value.trim() !== '') {
                            lua += '            ["' + field + '"] = "' + this.escapeLuaString(value) + '",\n';
                        } else if (typeof value === 'number') {
                            lua += '            ["' + field + '"] = ' + value + ',\n';
                        }
                    }
                }
                
                lua += '        },\n';
            }
            
            lua += '    },\n';
        }
        lua += '}\n\n';
        
        lua += 'p.card = card\n';
        lua += 'p.cardOrder = cardOrder\n\n';
        lua += 'return p\n';
        
        return lua;
    },

    updateCode: function() {
        var code = this.generateLuaCode();
        $('#ce-code-display').val(code);
    },

    copyCode: function() {
        var codeDisplay = document.getElementById('ce-code-display');
        codeDisplay.select();
        document.execCommand('copy');
        alert('代码已复制到剪贴板!');
    },

    loadAllCards: function() {
        var self = this;
        
        // 搜索所有 模块:卡牌/+角色名 的页面
        this.api.get({
            action: 'query',
            list: 'allpages',
            apprefix: '卡牌/',
            apnamespace: 828, // Module namespace
            aplimit: 'max'
        }).done(function(data) {
            if (data.query && data.query.allpages) {
                var pages = data.query.allpages;
                var loadPromises = [];
                
                pages.forEach(function(page) {
                    loadPromises.push(self.loadCardModule(page.title));
                });
                
                $.when.apply($, loadPromises).done(function() {
                    self.updateCardList();
                    self.updateCode();
                    alert('成功加载 ' + self.cards.length + ' 张卡牌!');
                });
            }
        });
    },

    loadCardModule: function(pageName) {
        var self = this;
        var deferred = $.Deferred();
        
        this.api.get({
            action: 'query',
            prop: 'revisions',
            titles: pageName,
            rvprop: 'content',
            rvslots: 'main'
        }).done(function(data) {
            var pages = data.query.pages;
            for (var pageId in pages) {
                var page = pages[pageId];
                if (page.revisions && page.revisions[0]) {
                    var content = page.revisions[0].slots.main['*'];
                    var cards = self.parseLuaModule(content);
                    self.cards = self.cards.concat(cards);
                }
            }
            deferred.resolve();
        }).fail(function() {
            deferred.resolve();
        });
        
        return deferred.promise();
    },

    parseLuaModule: function(content) {
        var cards = [];
        
        try {
            // 提取卡牌数据
            var cardMatch = content.match(/local\s+card\s*=\s*\{([\s\S]*?)\}/);
            if (!cardMatch) return cards;
            
            var cardContent = cardMatch[1];
            
            // 简化的解析逻辑 - 提取卡牌名称
            var nameMatches = cardContent.match(/\["([^"]+)"\]\s*=\s*\{/g);
            if (nameMatches) {
                nameMatches.forEach(function(match) {
                    var name = match.match(/\["([^"]+)"\]/)[1];
                    cards.push({
                        name: name,
                        variants: [{}] // 简化处理
                    });
                });
            }
        } catch (e) {
            console.error('解析错误:', e);
        }
        
        return cards;
    },

    saveToWiki: function() {
        if (this.cards.length === 0) {
            alert('没有数据可保存!');
            return;
        }
        
        var self = this;
        var characterName = prompt('请输入角色名称(将保存为"模块:卡牌/角色名"):');
        
        if (!characterName) return;
        
        var pageName = '模块:卡牌/' + characterName;
        var content = this.generateLuaCode();
        
        this.api.postWithToken('csrf', {
            action: 'edit',
            title: pageName,
            text: content,
            summary: '通过卡牌编辑器更新'
        }).done(function() {
            alert('成功保存到 ' + pageName + '!');
        }).fail(function(error) {
            alert('保存失败:' + error);
        });
    }
};