卡厄思
梦
境
菜单
首页
回到首页
WIKI工具
全站样式
全站JS
修改导航栏
测试
沙盒
可视化管理器
战斗员管理器
卡牌管理器
伙伴管理器
装备管理器
词典管理器
图鉴
战斗员
伙伴
装备
怪物卡牌
中立卡牌
词典
小工具
配队模拟器
节奏榜生成器
搜索
链入页面
相关更改
特殊页面
页面信息
最近更改
登录
MediaWiki
查看“︁Card.js”︁的源代码
←
MediaWiki:Card.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。 如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
(function() { // 确保jQuery和MediaWiki API已加载 mw.loader.using(['mediawiki.api', 'mediawiki.util', 'jquery.ui'], function() { $(document).ready(function() { // 卡牌编辑器对象 var CardEditor = { characters: {}, // 存储所有角色的卡牌数据 currentCharacter: null, // 当前选中的角色 currentCard: null, currentVariantIndex: null, api: new mw.Api(), init: function() { // 清空占位符 $('#mw-content-text').empty(); this.createUI(); this.bindEvents(); this.loadCharacterList(); }, 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-row">', '<div class="ce-label">当前战斗员:</div>', '<div class="ce-select-wrapper">', '<input type="text" id="ce-character-select" class="ce-select-input" placeholder="选择或输入新战斗员..." readonly>', '<div class="ce-select-dropdown" id="ce-character-dropdown" style="display:none;"></div>', '</div>', '<span class="ce-btn ce-btn-small ce-btn-primary" id="ce-new-character" style="margin-left: 10px;">新建</span>', '</div>', '</div>', '<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" style="display:none;">', '<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" style="display:none;">', '<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" style="display:none;">', '<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" style="display:none;">', '<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">', '<span class="ce-btn ce-btn-small ce-btn-blue" id="ce-blue-text">蓝色文本</span>', '<span class="ce-btn ce-btn-small ce-btn-green" id="ce-green-text">绿色文本</span>', '<span class="ce-btn ce-btn-small ce-btn-lime" id="ce-green-stroke">绿色描边</span>', '<span class="ce-btn ce-btn-small ce-btn-orange" id="ce-insert-br">插入换行</span>', '</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">', '<span class="ce-btn ce-btn-primary" id="ce-add-card">添加卡牌</span>', '<span class="ce-btn ce-btn-primary" id="ce-add-variant">添加变体</span>', '<span class="ce-btn" id="ce-save-data">保存数据</span>', '<span class="ce-btn" id="ce-clear-form">清空表单</span>', '</div>', '</div>', // 中间列表区 '<div class="ce-middle">', '<div class="ce-group">', '<div class="ce-group-title">卡牌列表 <span class="ce-hint">(拖动调整顺序)</span></div>', '<div class="ce-list-container">', '<div id="ce-card-list" class="ce-list ce-sortable"></div>', '</div>', '</div>', '<div class="ce-group">', '<div class="ce-group-title">变体列表 <span class="ce-hint">(拖动调整顺序)</span></div>', '<div class="ce-list-container">', '<div id="ce-variant-list" class="ce-list ce-sortable"></div>', '</div>', '</div>', '<div class="ce-buttons">', '<span class="ce-btn ce-btn-danger" id="ce-delete-card">删除卡牌</span>', '<span class="ce-btn ce-btn-danger" id="ce-delete-variant">删除变体</span>', '</div>', '</div>', // 右侧代码区 '<div class="ce-right">', '<div class="ce-group">', '<div class="ce-group-title">Lua代码预览 - <span id="ce-code-character">未选择战斗员</span></div>', '<textarea id="ce-code-display" class="ce-code" readonly></textarea>', '</div>', '<div class="ce-buttons">', '<span class="ce-btn" id="ce-reload-character">重新加载</span>', '<span class="ce-btn ce-btn-primary" id="ce-save-to-wiki">保存到Wiki</span>', '<span class="ce-btn" id="ce-copy-code">复制代码</span>', '<span class="ce-btn ce-btn-danger" id="ce-delete-character">删除战斗员</span>', '</div>', '</div>', '</div>', '</div>', '<style>', '.ce-hint { font-size: 12px; color: #666; font-weight: normal; }', '.ce-list-item { position: relative; cursor: move; }', '.ce-list-item.ui-sortable-helper { background: #e3f2fd; border: 2px solid #2196F3; }', '.ce-list-item.ui-sortable-placeholder { background: #f5f5f5; border: 2px dashed #ccc; visibility: visible !important; }', '.ce-list-item.selected { background: #e3f2fd; }', '</style>' ].join(''); $('#mw-content-text').html(html); }, bindEvents: function() { var self = this; // 自定义下拉框事件 $(document).on('click', '.ce-select-input', function() { var dropdown = $(this).siblings('.ce-select-dropdown'); $('.ce-select-dropdown').not(dropdown).hide(); dropdown.toggle(); }); $(document).on('click', '.ce-select-option', 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', '#ce-character-dropdown .ce-select-option', function() { var character = $(this).data('value'); self.selectCharacter(character); }); // 点击其他地方关闭下拉框 $(document).on('click', function(e) { if (!$(e.target).closest('.ce-select-wrapper').length) { $('.ce-select-dropdown').hide(); } }); // 按钮事件 $('#ce-new-character').on('click', function() { self.createNewCharacter(); }); $('#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-reload-character').on('click', function() { self.reloadCurrentCharacter(); }); $('#ce-save-to-wiki').on('click', function() { self.saveToWiki(); }); $('#ce-copy-code').on('click', function() { self.copyCode(); }); $('#ce-delete-character').on('click', function() { self.deleteCharacter(); }); // 文本格式化按钮 $('#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); } }); // 初始化拖拽排序 this.initSortable(); }, initSortable: function() { var self = this; // 卡牌列表排序 $('#ce-card-list').sortable({ items: '.ce-list-item', placeholder: 'ce-list-item ui-sortable-placeholder', update: function(event, ui) { self.onCardListReorder(); } }); // 变体列表排序 $('#ce-variant-list').sortable({ items: '.ce-list-item:not(.ce-no-sort)', placeholder: 'ce-list-item ui-sortable-placeholder', update: function(event, ui) { self.onVariantListReorder(); } }); }, onCardListReorder: function() { if (!this.currentCharacter) return; var newOrder = []; $('#ce-card-list .ce-list-item').each(function() { var index = $(this).data('index'); newOrder.push(index); }); // 重新排序卡牌数组 var cards = this.characters[this.currentCharacter]; var reorderedCards = []; for (var i = 0; i < newOrder.length; i++) { reorderedCards.push(cards[newOrder[i]]); } this.characters[this.currentCharacter] = reorderedCards; // 更新当前选中的卡牌引用 if (this.currentCard) { var currentCardIndex = reorderedCards.indexOf(this.currentCard); if (currentCardIndex === -1) { this.currentCard = null; this.currentVariantIndex = null; } } this.updateCardList(); this.updateCode(); }, onVariantListReorder: function() { if (!this.currentCard) return; var newOrder = []; $('#ce-variant-list .ce-list-item').each(function() { var index = $(this).data('index'); newOrder.push(index); }); // 重新排序变体数组 var variants = this.currentCard.variants; var reorderedVariants = []; for (var i = 0; i < newOrder.length; i++) { reorderedVariants.push(variants[newOrder[i]]); } this.currentCard.variants = reorderedVariants; // 更新当前选中的变体索引 if (this.currentVariantIndex !== null) { var oldVariant = variants[this.currentVariantIndex]; this.currentVariantIndex = reorderedVariants.indexOf(oldVariant); } this.updateVariantList(); this.updateCode(); }, selectCharacter: function(character) { this.currentCharacter = character; $('#ce-character-select').val(character); $('#ce-code-character').text(character); // 清空当前数据 this.currentCard = null; this.currentVariantIndex = null; this.clearForm(); // 更新显示 this.updateCardList(); this.updateVariantList(); this.updateCode(); }, createNewCharacter: function() { var character = prompt('请输入新战斗员的名称:'); if (!character || character.trim() === '') return; character = character.trim(); // 检查是否已存在 if (this.characters[character]) { alert('战斗员 "' + character + '" 已存在!'); return; } // 创建新战斗员 this.characters[character] = []; this.updateCharacterDropdown(); this.selectCharacter(character); alert('新战斗员 "' + character + '" 创建成功!'); }, deleteCharacter: function() { if (!this.currentCharacter) { alert('请先选择一个战斗员!'); return; } if (!confirm('确定要删除战斗员 "' + this.currentCharacter + '" 及其所有卡牌吗?\n此操作不可恢复!')) { return; } delete this.characters[this.currentCharacter]; this.currentCharacter = null; this.currentCard = null; this.currentVariantIndex = null; $('#ce-character-select').val(''); $('#ce-code-character').text('未选择战斗员'); this.updateCharacterDropdown(); this.clearForm(); this.updateCardList(); this.updateVariantList(); this.updateCode(); alert('战斗员删除成功!'); }, loadCharacterList: function() { var self = this; $('#ce-character-dropdown').html('<div class="ce-loading">正在加载战斗员列表...</div>'); // 搜索所有 模块:卡牌/+角色名 的页面 this.api.get({ action: 'query', list: 'allpages', apprefix: '卡牌/', apnamespace: 828, // Module namespace aplimit: 'max' }).then(function(data) { if (data.query && data.query.allpages) { var pages = data.query.allpages; var characterPromises = []; // 初始化空字典 self.characters = {}; for (var i = 0; i < pages.length; i++) { var title = pages[i].title; var character = title.replace('模块:卡牌/', ''); self.characters[character] = []; // 加载每个角色的数据 characterPromises.push(self.loadCharacterData(character)); } // 等待所有角色数据加载完成 $.when.apply($, characterPromises).then(function() { self.updateCharacterDropdown(); }); } else { self.updateCharacterDropdown(); } }).fail(function() { $('#ce-character-dropdown').html('<div class="ce-error">加载失败,请稍后重试</div>'); }); }, loadCharacterData: function(character) { var self = this; var pageName = '模块:卡牌/' + character; return this.api.get({ action: 'query', prop: 'revisions', titles: pageName, rvprop: 'content', rvlimit: 1 }).then(function(data) { if (data.query && data.query.pages) { for (var pageId in data.query.pages) { var page = data.query.pages[pageId]; if (page.revisions && page.revisions[0]) { var content = page.revisions[0]['*']; self.characters[character] = self.parseCardData(content); } } } }); }, reloadCurrentCharacter: function() { if (!this.currentCharacter) { alert('请先选择一个战斗员!'); return; } var self = this; this.loadCharacterData(this.currentCharacter).then(function() { self.updateCardList(); self.updateVariantList(); self.updateCode(); alert('战斗员 "' + self.currentCharacter + '" 的数据已重新加载!'); }); }, updateCharacterDropdown: function() { var html = '<div class="ce-select-option" data-value="">请选择战斗员</div>'; var characters = Object.keys(this.characters).sort(); for (var i = 0; i < characters.length; i++) { var character = characters[i]; var cardCount = this.characters[character].length; html += '<div class="ce-select-option" data-value="' + character + '">' + character + ' (' + cardCount + ' 张卡牌)</div>'; } $('#ce-character-dropdown').html(html); }, 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, 10); } } 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) { $('#ce-name').val(card.name || ''); if (card.variants && card.variants[variantIndex]) { var variant = card.variants[variantIndex]; var isVariant = variant['卡组'] === '灵光一闪' && variantIndex > 0; // 设置字段是否可编辑 $('#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() { if (!this.currentCharacter) { alert('请先选择或创建一个战斗员!'); return; } var cardData = this.getCardData(); if (!cardData.name) { alert('卡牌名称不能为空!'); return; } this.characters[this.currentCharacter].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 || !this.currentCharacter) { alert('请先选择要删除的卡牌!'); return; } if (confirm('确定要删除卡牌 "' + this.currentCard.name + '" 吗?')) { var cards = this.characters[this.currentCharacter]; var index = cards.indexOf(this.currentCard); 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) { if (!this.currentCharacter) return; // 由于重排序后,index对应的是DOM中的位置,需要找到对应的实际卡牌 var $item = $('#ce-card-list .ce-list-item').eq(index); var actualIndex = $item.data('original-index'); this.currentCard = this.characters[this.currentCharacter][actualIndex]; this.currentVariantIndex = 0; this.updateVariantList(); this.setCardData(this.currentCard, 0); }, onVariantSelected: function(index) { if (!this.currentCard) return; // 由于重排序后,index对应的是DOM中的位置,需要找到对应的实际变体 var $item = $('#ce-variant-list .ce-list-item').eq(index); var actualIndex = $item.data('original-index'); this.currentVariantIndex = actualIndex; this.setCardData(this.currentCard, actualIndex); }, updateCardList: function() { var html = ''; if (this.currentCharacter && this.characters[this.currentCharacter]) { var cards = this.characters[this.currentCharacter]; for (var i = 0; i < cards.length; i++) { var card = cards[i]; var selected = (card === this.currentCard) ? ' selected' : ''; html += '<div class="ce-list-item' + selected + '" data-index="' + i + '" data-original-index="' + i + '">' + '<span class="ce-drag-handle">≡ </span>' + card.name + '</div>'; } } if (html === '') { html = '<div class="ce-loading">暂无卡牌数据</div>'; } $('#ce-card-list').html(html); // 重新初始化排序 $('#ce-card-list').sortable('refresh'); }, 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 + ' (灵光一闪)'; var selected = (i === this.currentVariantIndex) ? ' selected' : ''; var noSort = i === 0 ? ' ce-no-sort' : ''; // 主卡牌不可排序 html += '<div class="ce-list-item' + selected + noSort + '" data-index="' + i + '" data-original-index="' + i + '">' + (i > 0 ? '<span class="ce-drag-handle">≡ </span>' : '') + name + '</div>'; } } $('#ce-variant-list').html(html); // 重新初始化排序 $('#ce-variant-list').sortable('refresh'); }, 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.currentCharacter || !this.characters[this.currentCharacter]) { return '-- 请先选择一个战斗员'; } var cards = this.characters[this.currentCharacter]; if (cards.length === 0) { return '-- ' + this.currentCharacter + ' 暂无卡牌数据'; } var lua = 'local p = {}\n\n'; // 生成 cardOrder lua += 'local cardOrder = {\n'; for (var i = 0; i < cards.length; i++) { var card = 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 < cards.length; i++) { var card = 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', '机制', '类型', '描述', '衍生卡牌']; // 如果是变体卡牌(非第一个且卡组为灵光一闪),只输出有差异的字段 if (j > 0 && variant['卡组'] === '灵光一闪') { var mainVariant = card.variants[0]; for (var k = 0; k < fieldOrder.length; k++) { var field = fieldOrder[k]; // 卡组字段必须输出 if (field === '卡组') { lua += ' ["' + field + '"] = "灵光一闪",\n'; continue; } // 只输出与主卡牌不同的字段 if (variant[field] !== undefined && variant[field] !== null && variant[field] !== mainVariant[field]) { var value = variant[field]; if (typeof value === 'string' && value.trim() !== '') { lua += ' ["' + field + '"] = "' + this.escapeLuaString(value) + '",\n'; } else if (typeof value === 'number' || value === 'X') { if (value === 'X') { lua += ' ["' + field + '"] = "X",\n'; } else { lua += ' ["' + field + '"] = ' + value + ',\n'; } } } } } else { // 主卡牌或非灵光一闪卡牌,输出所有非空字段 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' || value === 'X') { if (value === 'X') { lua += ' ["' + field + '"] = "X",\n'; } else { lua += ' ["' + field + '"] = ' + value + ',\n'; } } } } } lua += ' },\n'; } lua += ' },\n'; } lua += '}\n\n'; lua += 'p.card = card\n'; lua += 'p.cardOrder = cardOrder\n\n'; lua += 'return p\n'; return lua; }, 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('代码已复制到剪贴板!'); }, parseCardData: function(luaContent) { var cards = []; try { // 移除注释 var cleanContent = luaContent.replace(/--[^\n]*/g, ''); // 提取 card 表 - 更精确的匹配 var cardTableMatch = cleanContent.match(/local\s+card\s*=\s*\{([\s\S]*?)\n\}\s*\n/); if (!cardTableMatch) { console.error('未找到 card 表'); return cards; } var cardTableContent = cardTableMatch[1]; var cardMap = {}; // 解析每个卡牌 // 使用更精确的正则表达式匹配卡牌名称和内容 var currentPos = 0; while (currentPos < cardTableContent.length) { // 查找卡牌名称 var nameMatch = cardTableContent.substring(currentPos).match(/^\s*\["([^"]+)"\]\s*=\s*\{/); if (!nameMatch) { break; } var cardName = nameMatch[1]; currentPos += nameMatch[0].length; // 查找该卡牌的结束位置 var braceCount = 1; var variantsStart = currentPos; var inString = false; var escape = false; for (var i = currentPos; i < cardTableContent.length && braceCount > 0; i++) { var char = cardTableContent[i]; if (escape) { escape = false; continue; } if (char === '\\') { escape = true; continue; } if (char === '"' && !escape) { inString = !inString; } if (!inString) { if (char === '{') { braceCount++; } else if (char === '}') { braceCount--; } } } var variantsEnd = i; var variantsContent = cardTableContent.substring(variantsStart, variantsEnd - 1); currentPos = variantsEnd; // 解析变体 var card = { name: cardName, variants: [] }; // 解析每个变体 var variantPos = 0; while (variantPos < variantsContent.length) { var variantMatch = variantsContent.substring(variantPos).match(/^\s*\{/); if (!variantMatch) { break; } variantPos += variantMatch[0].length; // 查找变体的结束位置 var variantBraceCount = 1; var variantStart = variantPos; var inVarString = false; var varEscape = false; for (var j = variantPos; j < variantsContent.length && variantBraceCount > 0; j++) { var vChar = variantsContent[j]; if (varEscape) { varEscape = false; continue; } if (vChar === '\\') { varEscape = true; continue; } if (vChar === '"' && !varEscape) { inVarString = !inVarString; } if (!inVarString) { if (vChar === '{') { variantBraceCount++; } else if (vChar === '}') { variantBraceCount--; } } } var variantEnd = j; var variantContent = variantsContent.substring(variantStart, variantEnd - 1); variantPos = variantEnd; // 解析变体字段 var variant = {}; // 匹配所有字段 var fieldRegex = /\["([^"]+)"\]\s*=\s*([^,]+)(?:,|$)/g; var fieldMatch; while ((fieldMatch = fieldRegex.exec(variantContent)) !== null) { var key = fieldMatch[1]; var value = fieldMatch[2].trim(); // 处理字符串值 if (value.startsWith('"') && value.endsWith('"')) { value = value.slice(1, -1) .replace(/\\"/g, '"') .replace(/\\\\/g, '\\') .replace(/\\n/g, '\n'); } // 处理 "X" 特殊情况 else if (value === '"X"') { value = 'X'; } // 处理数字 else if (!isNaN(value)) { value = parseInt(value, 10); } variant[key] = value; } if (Object.keys(variant).length > 0) { card.variants.push(variant); } } if (card.variants.length > 0) { cardMap[cardName] = card; } } // 提取 cardOrder var orderMatch = cleanContent.match(/local\s+cardOrder\s*=\s*\{([^}]+)\}/); if (orderMatch) { var orderData = orderMatch[1]; var order = []; var orderRegex = /"([^"]+)"/g; var orderMatch2; while ((orderMatch2 = orderRegex.exec(orderData)) !== null) { order.push(orderMatch2[1]); } // 按照 cardOrder 排序 order.forEach(function(cardName) { if (cardMap[cardName]) { cards.push(cardMap[cardName]); } }); // 添加不在 cardOrder 中的卡牌 Object.keys(cardMap).forEach(function(cardName) { var found = false; for (var i = 0; i < cards.length; i++) { if (cards[i].name === cardName) { found = true; break; } } if (!found) { cards.push(cardMap[cardName]); } }); } else { // 如果没有 cardOrder,按照出现顺序 Object.keys(cardMap).forEach(function(cardName) { cards.push(cardMap[cardName]); }); } console.log('成功解析 ' + cards.length + ' 张卡牌'); } catch (e) { console.error('解析卡牌数据失败:', e); } return cards; }, saveToWiki: function() { if (!this.currentCharacter) { alert('请先选择一个战斗员!'); return; } var cards = this.characters[this.currentCharacter]; if (cards.length === 0) { alert('当前战斗员没有卡牌数据!'); return; } var pageName = '模块:卡牌/' + this.currentCharacter; var luaCode = this.generateLuaCode(); if (!confirm('确定要保存到 ' + pageName + ' 吗?\n这将覆盖现有内容!')) { return; } var self = this; this.api.postWithToken('csrf', { action: 'edit', title: pageName, text: luaCode, summary: '通过卡牌编辑器更新 ' + this.currentCharacter + ' 的卡牌数据', recreate: true }).done(function() { alert('保存成功!\n页面:' + pageName); // 更新下拉列表中的卡牌数量 self.updateCharacterDropdown(); }).fail(function(code, error) { alert('保存失败:' + (error.error ? error.error.info : code)); }); } }; // 添加CSS样式 var style = document.createElement('style'); style.textContent = [ '#card-editor { margin: 20px 0; }', '.ce-container { display: flex; gap: 20px; }', '.ce-left, .ce-middle, .ce-right { flex: 1; }', '.ce-group { margin-bottom: 20px; background: #f8f9fa; border: 1px solid #ddd; border-radius: 5px; padding: 15px; }', '.ce-group-title { font-weight: bold; font-size: 16px; margin-bottom: 10px; color: #333; }', '.ce-row { display: flex; align-items: center; margin-bottom: 10px; }', '.ce-label { width: 100px; font-weight: bold; color: #555; flex-shrink: 0; }', '.ce-input, .ce-textarea, .ce-select-input { flex: 1; padding: 8px 12px; border: 1px solid #ccc; border-radius: 3px; font-size: 14px; }', '.ce-textarea { min-height: 100px; resize: vertical; }', '.ce-code { width: 100%; height: 500px; font-family: monospace; font-size: 12px; }', '.ce-buttons { text-align: center; margin-top: 15px; }', '.ce-btn { display: inline-block; padding: 8px 16px; margin: 0 5px; background: #36c; color: white; border: none; border-radius: 3px; cursor: pointer; font-size: 14px; }', '.ce-btn:hover { background: #447ff5; }', '.ce-btn-primary { background: #0645ad; }', '.ce-btn-primary:hover { background: #0b61d4; }', '.ce-btn-danger { background: #d33; }', '.ce-btn-danger:hover { background: #e74c3c; }', '.ce-btn-small { padding: 4px 8px; font-size: 12px; margin: 0 2px; }', '.ce-btn-blue { background: #2196F3; }', '.ce-btn-green { background: #4CAF50; }', '.ce-btn-lime { background: #8BC34A; }', '.ce-btn-orange { background: #FF9800; }', '.ce-list-container { height: 250px; overflow-y: auto; border: 1px solid #ddd; border-radius: 3px; background: white; }', '.ce-list { padding: 10px; }', '.ce-list-item { padding: 8px 12px; margin-bottom: 5px; background: #f5f5f5; border-radius: 3px; cursor: pointer; transition: background 0.2s; }', '.ce-list-item:hover { background: #e8e8e8; }', '.ce-list-item.selected { background: #e3f2fd; color: #1976D2; font-weight: bold; }', '.ce-loading { text-align: center; padding: 20px; color: #666; }', '.ce-error { text-align: center; padding: 20px; color: #d33; }', '.ce-select-wrapper { position: relative; flex: 1; }', '.ce-select-input { cursor: pointer; background: white url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiI+PHBhdGggZmlsbD0iIzMzMyIgZD0iTTExIDQgNiA5IDEgNCIvPjwvc3ZnPg==") no-repeat right 10px center; background-size: 12px; padding-right: 30px; }', '.ce-select-dropdown { position: absolute; top: 100%; left: 0; right: 0; background: white; border: 1px solid #ccc; border-top: none; border-radius: 0 0 3px 3px; max-height: 200px; overflow-y: auto; z-index: 1000; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }', '.ce-select-option { padding: 8px 12px; cursor: pointer; transition: background 0.2s; }', '.ce-select-option:hover { background: #f5f5f5; }', '.ce-desc-wrapper { flex: 1; }', '.ce-format-buttons { margin-bottom: 5px; }', 'input[disabled], textarea[disabled], select[disabled] { background-color: #f0f0f0; cursor: not-allowed; }', '.ce-drag-handle { color: #999; margin-right: 5px; cursor: move; font-weight: bold; }', '.ce-no-sort { cursor: default; }', '.ce-no-sort .ce-drag-handle { display: none; }' ].join('\n'); document.head.appendChild(style); // 初始化编辑器 CardEditor.init(); }); }); })();
该页面使用的模板:
模板:图标
(
查看源代码
)
模板:描边
(
查看源代码
)
模板:描边/颜色
(
查看源代码
)
模板:文本
(
查看源代码
)
模板:词典
(
查看源代码
)
模块:文本
(
查看源代码
)
模块:词典
(
查看源代码
)
模块:词典/data
(
查看源代码
)
返回
MediaWiki:Card.js
。