卡厄思
梦
境
菜单
首页
回到首页
WIKI工具
全站样式
全站JS
修改导航栏
测试
沙盒
可视化管理器
战斗员管理器
卡牌管理器
伙伴管理器
装备管理器
词典管理器
图鉴
战斗员
伙伴
装备
怪物卡牌
中立卡牌
词典
小工具
配队模拟器
节奏榜生成器
搜索
链入页面
相关更改
特殊页面
页面信息
最近更改
登录
MediaWiki
查看“︁Card.js”︁的源代码
←
MediaWiki:Card.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。 如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
/** * MediaWiki卡牌编辑器 * 用于管理"模块:卡牌/角色名"页面 * 放置于 MediaWiki:card.js */ (function() { 'use strict'; // 检查是否在正确的页面加载 if (mw.config.get('wgCanonicalSpecialPageName') !== 'Blankpage' || !window.location.href.includes('卡牌管理')) { return; } var CardEditor = { cards: [], currentCard: null, currentVariantIndex: null, api: new mw.Api(), // 初始化 init: function() { this.createUI(); this.loadAllCards(); this.bindEvents(); }, // 创建UI界面 createUI: function() { var $container = $('<div>').attr('id', 'card-editor-container').css({ 'max-width': '1400px', 'margin': '20px auto', 'font-family': 'Microsoft YaHei, 微软雅黑, sans-serif' }); // 添加样式 this.addStyles(); // 创建主布局 var $mainLayout = $('<div>').addClass('card-editor-layout'); // 左侧:输入区 var $leftPanel = this.createInputArea(); // 中间:列表区 var $middlePanel = this.createListArea(); // 右侧:代码显示区 var $rightPanel = this.createCodeArea(); $mainLayout.append($leftPanel, $middlePanel, $rightPanel); $container.append($mainLayout); // 清空页面内容并添加编辑器 $('#mw-content-text').empty().append($container); }, // 添加CSS样式 addStyles: function() { var css = ` .card-editor-layout { display: flex; gap: 15px; margin-top: 20px; } .card-editor-panel { flex: 1; background: #fff; border: 1px solid #ddd; border-radius: 4px; padding: 15px; } .card-editor-panel.left { flex: 2; } .card-editor-panel.middle { flex: 1; } .card-editor-panel.right { flex: 2; } .card-group { border: 1px solid #ddd; border-radius: 4px; padding: 15px; margin-bottom: 15px; background: #fafafa; } .card-group-title { font-size: 16px; font-weight: bold; color: #555; margin-bottom: 12px; padding-bottom: 8px; border-bottom: 2px solid #4a90e2; } .card-field-row { display: flex; align-items: center; margin-bottom: 10px; } .card-field-label { min-width: 100px; color: #555; font-size: 13px; } .card-field-input { flex: 1; } .card-field-input input, .card-field-input select, .card-field-input textarea { width: 100%; padding: 6px 10px; border: 1px solid #ddd; border-radius: 3px; font-size: 13px; font-family: Microsoft YaHei, 微软雅黑, sans-serif; } .card-field-input textarea { resize: vertical; min-height: 80px; } .card-button { padding: 8px 16px; border: none; border-radius: 3px; cursor: pointer; font-size: 13px; font-family: Microsoft YaHei, 微软雅黑, sans-serif; transition: background-color 0.2s; } .card-button-primary { background-color: #4a90e2; color: white; } .card-button-primary:hover { background-color: #357abd; } .card-button-success { background-color: #5cb85c; color: white; } .card-button-success:hover { background-color: #4cae4c; } .card-button-danger { background-color: #d9534f; color: white; } .card-button-danger:hover { background-color: #c9302c; } .card-button-info { background-color: #2196F3; color: white; padding: 4px 10px; font-size: 12px; } .card-button-row { display: flex; gap: 8px; margin-top: 10px; } .card-list { border: 1px solid #ddd; border-radius: 3px; max-height: 300px; overflow-y: auto; } .card-list-item { padding: 10px; cursor: pointer; border-bottom: 1px solid #eee; transition: background-color 0.2s; } .card-list-item:hover { background-color: #f5f5f5; } .card-list-item.active { background-color: #e3f2fd; color: #333; } .card-code-display { background-color: #2b2b2b; color: #a9b7c6; font-family: Consolas, Monaco, monospace; padding: 15px; border-radius: 3px; overflow: auto; max-height: 600px; font-size: 12px; white-space: pre; } .card-format-buttons { display: flex; gap: 5px; margin-bottom: 5px; } .loading-indicator { text-align: center; padding: 20px; color: #666; } `; $('<style>').text(css).appendTo('head'); }, // 创建输入区域 createInputArea: function() { var $panel = $('<div>').addClass('card-editor-panel left'); var $group = $('<div>').addClass('card-group'); var $title = $('<div>').addClass('card-group-title').text('卡牌数据'); $group.append($title); // 卡牌名称 var $nameRow = this.createFieldRow('卡牌名称:', '<input type="text" id="card-name" placeholder="请输入卡牌名称...">'); $group.append($nameRow); // 卡组类型 var $deckRow = this.createFieldRow('卡组类型:', '<select id="card-deck"><option value="">请选择</option><option>起始卡牌</option><option>独特卡牌</option><option>灵光一闪</option><option>衍生卡牌</option></select>'); $group.append($deckRow); // 图片文件 var $artRow = this.createFieldRow('图片文件:', '<input type="text" id="card-art" placeholder="例如: 角色名_卡牌名.png">'); $group.append($artRow); // 属性 var $attrRow = this.createFieldRow('属性:', '<select id="card-attr"><option value="">请选择</option><option>热情</option><option>秩序</option><option>正义</option><option>本能</option><option>虚无</option></select>'); $group.append($attrRow); // 稀有度 var $rarityRow = this.createFieldRow('稀有度:', '<select id="card-rarity"><option value="">请选择</option><option>白</option><option>蓝</option><option>橙</option><option>彩</option></select>'); $group.append($rarityRow); // AP var $apRow = this.createFieldRow('AP (行动点):', '<input type="text" id="card-ap" placeholder="输入AP数值或X...">'); $group.append($apRow); // 类型 var $typeRow = this.createFieldRow('卡牌类型:', '<select id="card-type"><option value="">请选择</option><option>攻击</option><option>技能</option><option>强化</option><option>状态异常</option></select>'); $group.append($typeRow); // 机制 var $mechanismRow = this.createFieldRow('卡牌机制:', '<input type="text" id="card-mechanism" placeholder="请输入卡牌机制...">'); $group.append($mechanismRow); // 描述标签和格式按钮 var $descLabel = $('<div>').addClass('card-field-row'); $descLabel.append($('<div>').addClass('card-field-label').text('卡牌描述:')); var $formatBtns = $('<div>').addClass('card-format-buttons'); $formatBtns.append( $('<button>').addClass('card-button card-button-info').text('蓝色文本') .click(function() { CardEditor.insertTextFormat('蓝'); }), $('<button>').addClass('card-button card-button-info').css('background-color', '#4CAF50') .text('绿色文本').click(function() { CardEditor.insertTextFormat('绿'); }), $('<button>').addClass('card-button card-button-info').css('background-color', '#66BB6A') .text('绿色描边').click(function() { CardEditor.insertStrokeFormat(); }) ); $descLabel.append($formatBtns); $group.append($descLabel); // 描述输入框 var $descRow = $('<div>').addClass('card-field-row'); $descRow.append($('<div>').addClass('card-field-input') .html('<textarea id="card-desc" placeholder="请输入卡牌描述..."></textarea>')); $group.append($descRow); // 衍生卡牌 var $derivedRow = this.createFieldRow('衍生卡牌:', '<input type="text" id="card-derived" placeholder="请输入衍生卡牌...">'); $group.append($derivedRow); $panel.append($group); // 按钮组 var $btnRow1 = $('<div>').addClass('card-button-row'); $btnRow1.append( $('<button>').addClass('card-button card-button-success').text('添加卡牌') .click(function() { CardEditor.addCard(); }), $('<button>').addClass('card-button card-button-success').text('添加变体') .click(function() { CardEditor.addVariant(); }) ); $panel.append($btnRow1); var $btnRow2 = $('<div>').addClass('card-button-row'); $btnRow2.append( $('<button>').addClass('card-button card-button-primary').text('保存数据') .click(function() { CardEditor.saveData(); }), $('<button>').addClass('card-button card-button-primary').text('清空表单') .click(function() { CardEditor.clearForm(); }) ); $panel.append($btnRow2); var $btnRow3 = $('<div>').addClass('card-button-row'); $btnRow3.append( $('<button>').addClass('card-button card-button-primary').text('保存到Wiki') .click(function() { CardEditor.saveToWiki(); }) ); $panel.append($btnRow3); return $panel; }, // 创建列表区域 createListArea: function() { var $panel = $('<div>').addClass('card-editor-panel middle'); // 卡牌列表 var $cardGroup = $('<div>').addClass('card-group'); $cardGroup.append($('<div>').addClass('card-group-title').text('卡牌列表')); $cardGroup.append($('<div>').addClass('card-list').attr('id', 'card-list')); $panel.append($cardGroup); // 变体列表 var $variantGroup = $('<div>').addClass('card-group'); $variantGroup.append($('<div>').addClass('card-group-title').text('变体列表')); $variantGroup.append($('<div>').addClass('card-list').attr('id', 'variant-list')); $panel.append($variantGroup); // 删除按钮 var $btnRow = $('<div>').addClass('card-button-row'); $btnRow.append( $('<button>').addClass('card-button card-button-danger').text('删除卡牌') .click(function() { CardEditor.deleteCard(); }), $('<button>').addClass('card-button card-button-danger').text('删除变体') .click(function() { CardEditor.deleteVariant(); }) ); $panel.append($btnRow); return $panel; }, // 创建代码显示区域 createCodeArea: function() { var $panel = $('<div>').addClass('card-editor-panel right'); var $group = $('<div>').addClass('card-group'); $group.append($('<div>').addClass('card-group-title').text('Lua代码预览')); $group.append($('<div>').addClass('card-code-display').attr('id', 'code-display') .text('-- 暂无数据')); $panel.append($group); // 按钮 var $btnRow = $('<div>').addClass('card-button-row'); $btnRow.append( $('<button>').addClass('card-button card-button-primary').text('复制代码') .click(function() { CardEditor.copyCode(); }), $('<button>').addClass('card-button card-button-primary').text('刷新列表') .click(function() { CardEditor.loadAllCards(); }) ); $panel.append($btnRow); return $panel; }, // 创建字段行 createFieldRow: function(label, inputHtml) { var $row = $('<div>').addClass('card-field-row'); $row.append($('<div>').addClass('card-field-label').text(label)); $row.append($('<div>').addClass('card-field-input').html(inputHtml)); return $row; }, // 绑定事件 bindEvents: function() { var self = this; // 卡牌列表点击 $('#card-list').on('click', '.card-list-item', function() { var index = $(this).data('index'); self.onCardSelected(index); }); // 变体列表点击 $('#variant-list').on('click', '.card-list-item', function() { var index = $(this).data('index'); self.onVariantSelected(index); }); }, // 插入文本格式 insertTextFormat: function(color) { var $desc = $('#card-desc'); var text = $desc.val(); var start = $desc[0].selectionStart; var end = $desc[0].selectionEnd; var selectedText = text.substring(start, end); var formatted = selectedText ? `{{文本|${color}|${selectedText}}}` : `{{文本|${color}|}}`; var newText = text.substring(0, start) + formatted + text.substring(end); $desc.val(newText); // 设置光标位置 var newPos = start + formatted.length - (selectedText ? 0 : 2); $desc[0].selectionStart = $desc[0].selectionEnd = newPos; $desc.focus(); }, // 插入描边格式 insertStrokeFormat: function() { var $desc = $('#card-desc'); var text = $desc.val(); var start = $desc[0].selectionStart; var end = $desc[0].selectionEnd; var selectedText = text.substring(start, end); var formatted = selectedText ? `{{描边|绿|${selectedText}}}` : `{{描边|绿|}}`; var newText = text.substring(0, start) + formatted + text.substring(end); $desc.val(newText); var newPos = start + formatted.length - (selectedText ? 0 : 2); $desc[0].selectionStart = $desc[0].selectionEnd = newPos; $desc.focus(); }, // 获取表单数据 getCardData: function() { var variant = {}; var art = $('#card-art').val().trim(); if (art) variant.art = art; var deck = $('#card-deck').val().trim(); if (deck) variant['卡组'] = deck; var attr = $('#card-attr').val().trim(); if (attr) variant['属性'] = attr; var rarity = $('#card-rarity').val().trim(); if (rarity) variant['稀有度'] = rarity; var ap = $('#card-ap').val().trim(); if (ap) { if (ap.toUpperCase() === 'X') { variant.AP = 'X'; } else if (/^\d+$/.test(ap)) { variant.AP = parseInt(ap); } else { variant.AP = ap; } } var mechanism = $('#card-mechanism').val().trim(); if (mechanism) variant['机制'] = mechanism; var type = $('#card-type').val().trim(); if (type) variant['类型'] = type; var desc = $('#card-desc').val().trim(); if (desc) variant['描述'] = desc; var derived = $('#card-derived').val().trim(); if (derived) variant['衍生卡牌'] = derived; return { name: $('#card-name').val().trim(), variants: Object.keys(variant).length > 0 ? [variant] : [{}] }; }, // 设置表单数据 setCardData: function(card, variantIndex) { variantIndex = variantIndex || 0; $('#card-name').val(card.name); if (variantIndex < card.variants.length) { var variant = card.variants[variantIndex]; var isVariant = variant['卡组'] === '灵光一闪'; // 设置字段是否可编辑 $('#card-name').prop('disabled', isVariant); $('#card-art').prop('disabled', isVariant); $('#card-attr').prop('disabled', isVariant); $('#card-rarity').prop('disabled', isVariant); $('#card-derived').prop('disabled', isVariant); // 设置值 $('#card-art').val(variant.art || ''); $('#card-deck').val(variant['卡组'] || ''); $('#card-attr').val(variant['属性'] || ''); $('#card-rarity').val(variant['稀有度'] || ''); $('#card-ap').val(variant.AP !== undefined ? variant.AP : ''); $('#card-mechanism').val(variant['机制'] || ''); $('#card-type').val(variant['类型'] || ''); $('#card-desc').val(variant['描述'] || ''); $('#card-derived').val(variant['衍生卡牌'] || ''); } }, // 清空表单 clearForm: function() { $('#card-name, #card-art, #card-ap, #card-mechanism, #card-desc, #card-derived').val(''); $('#card-deck, #card-attr, #card-rarity, #card-type').val(''); $('#card-name, #card-art, #card-attr, #card-rarity, #card-derived').prop('disabled', false); this.currentCard = null; this.currentVariantIndex = null; }, // 添加卡牌 addCard: function() { var cardData = this.getCardData(); if (!cardData.name) { mw.notify('卡牌名称不能为空!', { type: 'error' }); return; } this.cards.push(cardData); this.currentCard = cardData; this.currentVariantIndex = 0; this.updateCardList(); this.updateVariantList(); this.updateCode(); this.clearForm(); mw.notify('卡牌"' + cardData.name + '"添加成功!', { type: 'success' }); }, // 添加变体 addVariant: function() { if (!this.currentCard) { mw.notify('请先选择一个卡牌!', { type: 'error' }); 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(); mw.notify('为"' + this.currentCard.name + '"添加变体成功!', { type: 'success' }); }, // 保存数据 saveData: function() { if (!this.currentCard || this.currentVariantIndex === null) { mw.notify('请先选择要保存的卡牌或变体!', { type: 'error' }); return; } var cardData = this.getCardData(); var isVariant = this.currentVariantIndex > 0; if (isVariant) { var variant = cardData.variants[0]; variant['卡组'] = '灵光一闪'; this.currentCard.variants[this.currentVariantIndex] = variant; } else { this.currentCard.name = cardData.name; this.currentCard.variants[0] = cardData.variants[0]; } this.updateCardList(); this.updateVariantList(); this.updateCode(); mw.notify('数据保存成功!', { type: 'success' }); }, // 删除卡牌 deleteCard: function() { if (!this.currentCard) { mw.notify('请先选择要删除的卡牌!', { type: 'error' }); return; } if (!confirm('确定要删除卡牌"' + this.currentCard.name + '"吗?')) { return; } var index = this.cards.indexOf(this.currentCard); if (index > -1) { this.cards.splice(index, 1); } this.currentCard = null; this.currentVariantIndex = null; this.updateCardList(); this.updateVariantList(); this.updateCode(); this.clearForm(); mw.notify('卡牌删除成功!', { type: 'success' }); }, // 删除变体 deleteVariant: function() { if (!this.currentCard || this.currentVariantIndex === null) { mw.notify('请先选择要删除的变体!', { type: 'error' }); return; } if (this.currentVariantIndex === 0) { mw.notify('不能删除主卡牌变体!', { type: 'error' }); return; } if (!confirm('确定要删除这个变体吗?')) { return; } this.currentCard.variants.splice(this.currentVariantIndex, 1); this.currentVariantIndex = 0; this.updateVariantList(); this.updateCode(); this.setCardData(this.currentCard, 0); mw.notify('变体删除成功!', { type: 'success' }); }, // 选择卡牌 onCardSelected: function(index) { this.currentCard = this.cards[index]; this.currentVariantIndex = 0; this.updateVariantList(); this.setCardData(this.currentCard, 0); $('#card-list .card-list-item').removeClass('active'); $('#card-list .card-list-item').eq(index).addClass('active'); }, // 选择变体 onVariantSelected: function(index) { if (!this.currentCard) return; this.currentVariantIndex = index; this.setCardData(this.currentCard, index); $('#variant-list .card-list-item').removeClass('active'); $('#variant-list .card-list-item').eq(index).addClass('active'); }, // 更新卡牌列表 updateCardList: function() { var $list = $('#card-list').empty(); this.cards.forEach(function(card, index) { var $item = $('<div>').addClass('card-list-item') .text(card.name) .data('index', index); $list.append($item); }); }, // 更新变体列表 updateVariantList: function() { var $list = $('#variant-list').empty(); if (this.currentCard) { this.currentCard.variants.forEach(function(variant, index) { var deck = variant['卡组'] || '未知'; var label = index === 0 ? '主卡牌 (' + deck + ')' : '变体 ' + index + ' (灵光一闪)'; var $item = $('<div>').addClass('card-list-item') .text(label) .data('index', index); $list.append($item); }); } }, // 生成Lua代码 generateLuaCode: function() { if (this.cards.length === 0) { return '-- 暂无数据'; } var lua = 'local p = {}\n\n'; // cardOrder lua += 'local cardOrder = {\n'; this.cards.forEach(function(card) { lua += ' "' + CardEditor.escapeLuaString(card.name) + '",\n'; }); lua += '}\n'; // card数据 lua += 'local card = {\n'; this.cards.forEach(function(card) { lua += ' ["' + CardEditor.escapeLuaString(card.name) + '"] = {\n'; card.variants.forEach(function(variant) { lua += ' {\n'; var fieldOrder = ['art', '卡组', '属性', '稀有度', 'AP', '机制', '类型', '描述', '衍生卡牌']; fieldOrder.forEach(function(field) { if (variant[field] !== undefined && variant[field] !== '') { var value = variant[field]; if (typeof value === 'string') { lua += ' ["' + field + '"] = "' + CardEditor.escapeLuaString(value) + '",\n'; } else { lua += ' ["' + field + '"] = ' + value + ',\n'; } } }); lua += ' },\n'; }); lua += ' },\n'; }); lua += '}\n\n'; lua += 'p.card = card\n'; lua += 'p.cardOrder = cardOrder\n\n'; lua += 'return p\n'; return lua; }, // 转义Lua字符串 escapeLuaString: function(str) { if (typeof str !== 'string') return str; return str.replace(/\\/g, '\\\\') .replace(/"/g, '\\"') .replace(/\n/g, '\\n'); }, // 更新代码显示 updateCode: function() { var code = this.generateLuaCode(); $('#code-display').text(code); }, // 复制代码 copyCode: function() { var code = $('#code-display').text(); var $temp = $('<textarea>').val(code).appendTo('body').select(); document.execCommand('copy'); $temp.remove(); mw.notify('代码已复制到剪贴板!', { type: 'success' }); }, // 从Wiki加载所有卡牌 loadAllCards: function() { var self = this; $('#code-display').html('<div class="loading-indicator">正在加载卡牌数据...</div>'); // 获取所有"模块:卡牌/"开头的页面 this.api.get({ action: 'query', list: 'allpages', apprefix: '卡牌/', apnamespace: 828, // 模块命名空间 aplimit: 500 }).done(function(data) { if (data.query && data.query.allpages) { var pages = data.query.allpages; self.loadCardsFromPages(pages); } else { mw.notify('未找到卡牌页面', { type: 'warn' }); self.updateCode(); } }).fail(function() { mw.notify('加载卡牌列表失败', { type: 'error' }); self.updateCode(); }); }, // 从页面列表加载卡牌 loadCardsFromPages: function(pages) { var self = this; var promises = []; pages.forEach(function(page) { var pageName = page.title; var promise = self.api.get({ action: 'query', prop: 'revisions', titles: pageName, rvprop: 'content', rvslots: 'main' }); promises.push(promise); }); Promise.all(promises).then(function(results) { self.cards = []; results.forEach(function(data) { if (data.query && data.query.pages) { var pageId = Object.keys(data.query.pages)[0]; var page = data.query.pages[pageId]; if (page.revisions && page.revisions[0]) { var content = page.revisions[0].slots.main['*']; var parsedCards = self.parseLuaContent(content); if (parsedCards.length > 0) { self.cards = self.cards.concat(parsedCards); } } } }); self.updateCardList(); self.updateCode(); mw.notify('成功加载 ' + self.cards.length + ' 张卡牌', { type: 'success' }); }).catch(function() { mw.notify('加载卡牌数据失败', { type: 'error' }); self.updateCode(); }); }, // 解析Lua内容 parseLuaContent: function(content) { var cards = []; try { // 提取cardOrder var cardOrderMatch = content.match(/local\s+cardOrder\s*=\s*\{([^}]+)\}/); var cardOrder = []; if (cardOrderMatch) { var matches = cardOrderMatch[1].match(/"([^"]+)"/g); if (matches) { cardOrder = matches.map(function(m) { return m.slice(1, -1); }); } } // 提取card表 var cardTableMatch = content.match(/local\s+card\s*=\s*\{(.+)\}\s*p\.card/s); if (!cardTableMatch) return cards; var cardContent = cardTableMatch[1]; // 提取所有卡牌名称 var allCardNames = this.extractAllCardNames(cardContent); // 合并cardOrder和实际卡牌名称 var finalCardNames = []; cardOrder.forEach(function(name) { if (allCardNames.indexOf(name) !== -1) { finalCardNames.push(name); allCardNames.splice(allCardNames.indexOf(name), 1); } }); finalCardNames = finalCardNames.concat(allCardNames); // 按顺序处理每个卡牌 var self = this; finalCardNames.forEach(function(cardName) { var variants = self.extractCardVariants(cardContent, cardName); if (variants.length > 0) { cards.push({ name: cardName, variants: variants }); } }); } catch (e) { console.error('解析Lua内容失败:', e); } return cards; }, // 提取所有卡牌名称 extractAllCardNames: function(cardContent) { var cardNames = []; var pattern = /\["([^"]+)"\]\s*=\s*\{/g; var match; while ((match = pattern.exec(cardContent)) !== null) { var name = match[1]; if (cardNames.indexOf(name) === -1) { cardNames.push(name); } } return cardNames; }, // 提取卡牌变体 extractCardVariants: function(cardContent, cardName) { var variants = []; // 转义特殊字符 var escapedName = cardName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); var pattern = new RegExp('\\["' + escapedName + '"\\]\\s*=\\s*\\{'); var match = pattern.exec(cardContent); if (!match) return variants; // 提取卡牌块 var startPos = match.index + match[0].length; var cardBlock = this.extractBalancedBraces(cardContent, startPos); if (!cardBlock) return variants; // 解析所有变体 var pos = 0; while (pos < cardBlock.length) { // 跳过空白 while (pos < cardBlock.length && /\s/.test(cardBlock[pos])) { pos++; } if (pos >= cardBlock.length) break; if (cardBlock[pos] === '{') { var variantContent = this.extractBalancedBraces(cardBlock, pos + 1); if (variantContent !== null) { var variant = this.parseVariant(variantContent); if (variant && Object.keys(variant).length > 0) { variants.push(variant); } pos += variantContent.length + 2; } else { pos++; } } else { pos++; } } return variants; }, // 提取平衡的大括号内容 extractBalancedBraces: function(text, startPos) { var braceCount = 1; var pos = startPos; var inString = false; var escapeNext = false; var result = []; while (pos < text.length && braceCount > 0) { var char = text[pos]; if (escapeNext) { result.push(char); escapeNext = false; pos++; continue; } if (char === '\\' && inString) { result.push(char); escapeNext = true; pos++; continue; } if (char === '"') { inString = !inString; result.push(char); pos++; continue; } if (!inString) { if (char === '{') { braceCount++; } else if (char === '}') { braceCount--; if (braceCount === 0) { break; } } } result.push(char); pos++; } if (braceCount !== 0) return null; return result.join(''); }, // 解析变体 parseVariant: function(variantContent) { var variant = {}; var pos = 0; while (pos < variantContent.length) { // 跳过空白和逗号 while (pos < variantContent.length && /[\s,]/.test(variantContent[pos])) { pos++; } if (pos >= variantContent.length) break; // 查找字段定义 if (variantContent[pos] === '[') { var fieldMatch = variantContent.substring(pos).match(/\["([^"]+)"\]\s*=\s*/); if (fieldMatch) { var fieldName = fieldMatch[1]; pos += fieldMatch[0].length; var result = this.extractFieldValue(variantContent, pos); if (result.value !== null) { variant[fieldName] = result.value; pos += result.length; } else { pos++; } } else { pos++; } } else { pos++; } } return variant; }, // 提取字段值 extractFieldValue: function(text, startPos) { var pos = startPos; // 跳过空白 while (pos < text.length && /\s/.test(text[pos])) { pos++; } if (pos >= text.length) { return { value: null, length: 0 }; } // 字符串值 if (text[pos] === '"') { pos++; var valueChars = []; var escapeNext = false; while (pos < text.length) { var char = text[pos]; if (escapeNext) { if (char === 'n') { valueChars.push('\n'); } else if (char === 't') { valueChars.push('\t'); } else if (char === '\\') { valueChars.push('\\'); } else if (char === '"') { valueChars.push('"'); } else { valueChars.push(char); } escapeNext = false; pos++; continue; } if (char === '\\') { escapeNext = true; pos++; continue; } if (char === '"') { pos++; break; } valueChars.push(char); pos++; } var value = valueChars.join(''); var length = pos - startPos; return { value: value, length: length }; } // 数字或其他值 else { var valueMatch = text.substring(pos).match(/([^,\n}\]]+)/); if (valueMatch) { var valueStr = valueMatch[1].trim(); var length = valueMatch[0].length; if (/^-?\d+$/.test(valueStr)) { return { value: parseInt(valueStr), length: length }; } else { return { value: valueStr, length: length }; } } } return { value: null, length: 0 }; }, // 保存到Wiki saveToWiki: function() { if (this.cards.length === 0) { mw.notify('没有数据可保存!', { type: 'error' }); return; } var characterName = prompt('请输入角色名称(将创建"模块:卡牌/角色名"页面):'); if (!characterName) return; var pageName = '模块:卡牌/' + characterName; var content = this.generateLuaCode(); var self = this; this.api.postWithToken('csrf', { action: 'edit', title: pageName, text: content, summary: '通过卡牌编辑器更新', contentformat: 'text/x-lua', contentmodel: 'Scribunto' }).done(function() { mw.notify('成功保存到页面: ' + pageName, { type: 'success' }); }).fail(function(code, result) { mw.notify('保存失败: ' + (result.error ? result.error.info : '未知错误'), { type: 'error' }); }); } }; // 在页面加载完成后初始化 $(function() { CardEditor.init(); }); })();
该页面使用的模板:
模板:图标
(
查看源代码
)
模板:描边
(
查看源代码
)
模板:描边/颜色
(
查看源代码
)
模板:文本
(
查看源代码
)
模板:词典
(
查看源代码
)
模块:文本
(
查看源代码
)
模块:词典
(
查看源代码
)
模块:词典/data
(
查看源代码
)
返回
MediaWiki:Card.js
。