MediaWiki:Card.js
来自卡厄思梦境WIKI
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
/**
* 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();
});
})();