Dictionary.js:修订间差异
来自卡厄思梦境WIKI
无编辑摘要 |
无编辑摘要 |
||
| 第1行: | 第1行: | ||
/** | |||
* MediaWiki词典编辑器 | |||
* 用于管理模块:词典/data中的词条数据 | |||
*/ | |||
(function() { | (function() { | ||
'use strict'; | 'use strict'; | ||
if (mw.config.get('wgPageName') !== 'MediaWiki:Dictionary') return; | // 只在MediaWiki:Dictionary页面运行 | ||
if (mw.config.get('wgPageName') !== 'MediaWiki:Dictionary') { | |||
return; | |||
} | |||
var DictManager = { | |||
api: new mw.Api(), | |||
MODULE_PAGE: '模块:词典/data', | |||
dictionaryData: {}, | |||
currentEditKey: null, | |||
currentEditIndex: null, | |||
// 类型选项 | |||
typeOptions: ['', '卡牌机制', '战斗员专属机制', 'buff', 'debuff'], | |||
colorOptions: ['', '白', '蓝', '红', '橙', '彩'], | |||
// 初始化 | |||
init: function() { | |||
<div class="dict- | this.createUI(); | ||
this.loadData(); | |||
}, | |||
// 创建UI | |||
createUI: function() { | |||
var container = document.createElement('div'); | |||
container.className = 'dict-editor'; | |||
container.innerHTML = ` | |||
<div class="dict-section"> | |||
<h3>词典管理器</h3> | |||
< | <div id="dict-message"></div> | ||
<div class="dict-tabs"> | |||
<div class="dict-tab active" data-tab="list">词条列表</div> | |||
<div class="dict-tab" data-tab="edit">编辑/新建</div> | |||
</div> | |||
<div id="tab-list" class="dict-tab-content active"> | |||
<div class="dict-button success" id="dict-create-new">新建词条</div> | |||
<div class="dict-button" id="dict-refresh">刷新数据</div> | |||
<div class="dict- | <div class="dict-button secondary" id="dict-save-module">保存到模块</div> | ||
<div id="dict-list-container" class="dict-loading">加载中...</div> | |||
</div> | </div> | ||
<div id="tab-edit" class="dict-tab-content"> | |||
<div id="dict-editor-container"></div> | |||
<div | |||
<div | |||
</div> | </div> | ||
</div> | </div> | ||
`; | |||
var content = document.getElementById('mw-content-text'); | |||
content.innerHTML = ''; | |||
content.appendChild(container); | |||
this.bindEvents(); | |||
}, | |||
// 绑定事件 | |||
bindEvents: function() { | |||
var self = this; | |||
// 标签切换 | |||
document.querySelectorAll('.dict-tab').forEach(function(tab) { | |||
tab.addEventListener('click', function() { | |||
self.switchTab(this.getAttribute('data-tab')); | |||
}); | |||
}); | |||
// 新建词条 | |||
document.getElementById('dict-create-new').addEventListener('click', function() { | |||
self.createNew(); | |||
}); | |||
// 刷新数据 | |||
document.getElementById('dict-refresh').addEventListener('click', function() { | |||
self.loadData(); | |||
}); | |||
// 保存到模块 | |||
document.getElementById('dict-save-module').addEventListener('click', function() { | |||
self.saveToModule(); | |||
}); | |||
}, | |||
// 切换标签 | |||
switchTab: function(tabName) { | |||
document.querySelectorAll('.dict-tab').forEach(function(tab) { | |||
tab.classList.remove('active'); | |||
}); | |||
document.querySelectorAll('.dict-tab-content').forEach(function(content) { | |||
content.classList.remove('active'); | |||
}); | |||
document.querySelector('[data-tab="' + tabName + '"]').classList.add('active'); | |||
document.getElementById('tab-' + tabName).classList.add('active'); | |||
}, | |||
// 加载数据 | |||
loadData: function() { | |||
var self = this; | |||
self.showMessage('加载中...', 'info'); | |||
this.api.get({ | |||
action: 'query', | |||
prop: 'revisions', | |||
titles: this.MODULE_PAGE, | |||
rvprop: 'content', | |||
rvslots: 'main', | |||
format: 'json' | |||
}).done(function(data) { | |||
var pages = data.query.pages; | |||
var pageId = Object.keys(pages)[0]; | |||
if (pageId === '-1') { | |||
self.showMessage('模块页面不存在', 'error'); | |||
return; | |||
} | |||
var content = pages[pageId].revisions[0].slots.main['*']; | |||
self.parseModuleData(content); | |||
self.renderList(); | |||
self.showMessage('数据加载成功', 'success'); | |||
}).fail(function() { | |||
self.showMessage('加载失败', 'error'); | |||
}); | }); | ||
} | }, | ||
// | // 解析模块数据 | ||
parseModuleData: function(content) { | |||
try { | |||
var match = content.match(/data\.dictionary\s*=\s*\{([\s\S]*?)\n\}/); | |||
if (!match) { | |||
this.dictionaryData = {}; | |||
return; | |||
} | |||
var dictContent = match[1]; | |||
this.dictionaryData = {}; | |||
// 使用正则匹配每个词条 | |||
var entryRegex = /$$"([^"]+)"$$\s*=\s*\{([\s\S]*?)\n\s{4}\}/g; | |||
var entryMatch; | |||
while ((entryMatch = entryRegex.exec(dictContent)) !== null) { | |||
var key = entryMatch[1]; | |||
var variantsContent = entryMatch[2]; | |||
this.dictionaryData[key] = []; | |||
// 匹配每个变体 | |||
var variantRegex = /\{[\s\S]*?$$"icon"$$\s*=\s*"([^"]*)"[\s\S]*?$$"类型"$$\s*=\s*"([^"]*)"[\s\S]*?$$"颜色"$$\s*=\s*"([^"]*)"[\s\S]*?$$"描述"$$\s*=\s*"([^"]*)"[\s\S]*?\}/g; | |||
var variantMatch; | |||
while ((variantMatch = variantRegex.exec(variantsContent)) !== null) { | |||
this.dictionaryData[key].push({ | |||
icon: variantMatch[1], | |||
类型: variantMatch[2], | |||
颜色: variantMatch[3], | |||
描述: variantMatch[4] | |||
}); | |||
} | |||
} | |||
console.log('解析完成:', this.dictionaryData); | |||
} catch (e) { | |||
console.error('解析错误:', e); | |||
this.dictionaryData = {}; | |||
} | } | ||
} | }, | ||
// 渲染列表 | |||
renderList: function() { | |||
var container = document.getElementById('dict-list-container'); | |||
if ( | if (Object.keys(this.dictionaryData).length === 0) { | ||
container.innerHTML = '<div class="dict-message info">暂无词条,点击"新建词条"开始创建</div>'; | |||
return; | |||
} | } | ||
var html = '<div class="dict-grid">'; | |||
for (var key in this.dictionaryData) { | |||
var variants = this.dictionaryData[key]; | |||
html += '<div class="dict-list-item" data-key="' + mw.html.escape(key) + '">'; | |||
html += '<strong>' + mw.html.escape(key) + '</strong>'; | |||
html += '<div style="margin-top: 5px; font-size: 12px; color: #72777d;">'; | |||
html += variants.length + ' 个变体'; | |||
html += '</div>'; | |||
html += '</div>'; | |||
} | } | ||
html += '</div>'; | |||
container.innerHTML = html; | |||
var self = this; | |||
document.querySelectorAll('.dict-list-item').forEach(function(item) { | |||
item.addEventListener('click', function() { | |||
var key = this.getAttribute('data-key'); | |||
self.editEntry(key); | |||
}); | |||
}); | }); | ||
} | }, | ||
// 新建词条 | |||
createNew: function() { | |||
this.currentEditKey = null; | |||
this.currentEditIndex = null; | |||
this.switchTab('edit'); | |||
this.renderEditor(); | |||
this.showMessage('请填写词条信息', 'info'); | |||
}, | |||
' | |||
' | |||
// 编辑词条 | |||
editEntry: function(key) { | |||
this.currentEditKey = key; | |||
this.switchTab('edit'); | |||
this.renderEditor(); | |||
}, | |||
// 渲染编辑器 | |||
renderEditor: function() { | |||
var self = this; | |||
var container = document.getElementById('dict-editor-container'); | |||
var html = '<h4>' + (this.currentEditKey ? '编辑词条: ' + mw.html.escape(this.currentEditKey) : '新建词条') + '</h4>'; | |||
if (!this.currentEditKey) { | |||
// 新建模式 | |||
html += '<div class="dict-form-group">'; | |||
html += '<label>词条名称 *</label>'; | |||
html += '<input type="text" class="dict-input" id="dict-entry-name" placeholder="例如: 粉碎">'; | |||
html += '</div>'; | |||
html += '<h4>变体信息</h4>'; | |||
html += '<div class="dict-field-row">'; | |||
html += this.renderField('icon', 'text', '图标', ''); | |||
} | html += this.renderField('type', 'select', '类型 *', '', this.typeOptions); | ||
html += this.renderField('color', 'select', '颜色 *', '', this.colorOptions); | |||
html += '</div>'; | |||
html += this.renderField('desc', 'textarea', '描述 *', ''); | |||
html += '<div style="margin-top: 20px;">'; | |||
html += '<div class="dict-button success" id="dict-save-new">保存词条</div>'; | |||
html += '<div class="dict-button secondary" id="dict-cancel-edit">取消</div>'; | |||
html += '</div>'; | |||
} else { | |||
// 编辑模式 - 显示所有变体 | |||
var variants = this.dictionaryData[this.currentEditKey]; | |||
html += '<div style="margin-bottom: 20px;">'; | |||
html += '<div class="dict-button success" id="dict-add-variant">添加新变体</div>'; | |||
html += '<div class="dict-button danger" id="dict-delete-entry">删除整个词条</div>'; | |||
html += '<div class="dict-button secondary" id="dict-back-to-list">返回列表</div>'; | |||
html += '</div>'; | |||
html += '<h4>现有变体</h4>'; | |||
variants.forEach(function(variant, index) { | |||
var colorClass = self.getColorClass(variant.颜色); | |||
html += '<div class="dict-variant" data-index="' + index + '">'; | |||
html += '<div class="dict-variant-header">'; | |||
html += '<span class="dict-badge ' + colorClass + '">' + mw.html.escape(variant.类型) + '</span>'; | |||
html += '<span class="dict-badge ' + colorClass + '">' + mw.html.escape(variant.颜色) + '</span>'; | |||
html += '<div class="dict-button" style="float: right; margin-left: 5px;" data-action="delete" data-index="' + index + '">删除</div>'; | |||
html += '<div class="dict-button" style="float: right;" data-action="edit" data-index="' + index + '">编辑</div>'; | |||
html += '</div>'; | |||
html += '<div class="dict-variant-desc">' + mw.html.escape(variant.描述) + '</div>'; | |||
if (variant.icon) { | |||
html += '<div class="dict-variant-icon">图标: ' + mw.html.escape(variant.icon) + '</div>'; | |||
} | |||
html += '</div>'; | |||
}); | |||
} | |||
html += '<div id="dict-preview-container"></div>'; | |||
container.innerHTML = html; | |||
this.initCustomSelects(); | |||
this.bindEditorEvents(); | |||
}, | |||
// 渲染表单字段 | |||
renderField: function(id, type, label, value, options) { | |||
var html = '<div class="dict-form-group">'; | |||
html += '<label>' + mw.html.escape(label) + '</label>'; | |||
if (type === 'select') { | |||
html += '<div class="dict-custom-select" id="dict-' + id + '" data-value="' + mw.html.escape(value) + '">'; | |||
html += '<div class="dict-select-display">' + (value || '请选择') + '</div>'; | |||
html += '<div class="dict-select-options">'; | |||
options.forEach(function(opt) { | |||
html += '<div class="dict-select-option" data-value="' + mw.html.escape(opt) + '">' + | |||
mw.html.escape(opt || '请选择') + '</div>'; | |||
}); | |||
html += '</div></div>'; | |||
} else if (type === 'textarea') { | |||
html += '<textarea class="dict-textarea" id="dict-' + id + '">' + mw.html.escape(value) + '</textarea>'; | |||
} else { | |||
html += '<input type="text" class="dict-input" id="dict-' + id + '" value="' + mw.html.escape(value) + '">'; | |||
} | |||
html += '</div>'; | |||
return html; | |||
}, | |||
if (! | // 初始化自定义选择器 | ||
initCustomSelects: function() { | |||
var self = this; | |||
} | |||
document.querySelectorAll('.dict-custom-select').forEach(function(select) { | |||
var display = select.querySelector('.dict-select-display'); | |||
display.addEventListener('click', function(e) { | |||
e.stopPropagation(); | |||
// 关闭其他选择器 | |||
document.querySelectorAll('.dict-custom-select').forEach(function(s) { | |||
if (s !== select) s.classList.remove('open'); | |||
}); | |||
select.classList.toggle('open'); | |||
}); | |||
select.querySelectorAll('.dict-select-option').forEach(function(option) { | |||
option.addEventListener('click', function(e) { | |||
e.stopPropagation(); | |||
var value = this.getAttribute('data-value'); | |||
select.setAttribute('data-value', value); | |||
display.textContent = this.textContent; | |||
select.classList.remove('open'); | |||
}); | |||
}); | |||
}); | |||
// 点击外部关闭 | |||
document.addEventListener('click', function() { | |||
document.querySelectorAll('.dict-custom-select').forEach(function(s) { | |||
s.classList.remove('open'); | |||
}); | |||
}); | |||
}, | |||
// 绑定编辑器事件 | |||
bindEditorEvents: function() { | |||
var self = this; | |||
var saveBtn = document.getElementById('dict-save-new'); | |||
} | if (saveBtn) { | ||
saveBtn.addEventListener('click', function() { | |||
self.saveNewEntry(); | |||
}); | |||
} | |||
var cancelBtn = document.getElementById('dict-cancel-edit'); | |||
if (cancelBtn) { | |||
cancelBtn.addEventListener('click', function() { | |||
self.switchTab('list'); | |||
}); | |||
} | |||
var addVariantBtn = document.getElementById('dict-add-variant'); | |||
if (addVariantBtn) { | |||
addVariantBtn.addEventListener('click', function() { | |||
self.showVariantForm(); | |||
}); | |||
} | |||
var deleteEntryBtn = document.getElementById('dict-delete-entry'); | |||
if (deleteEntryBtn) { | |||
deleteEntryBtn.addEventListener('click', function() { | |||
if (confirm('确定要删除整个词条"' + self.currentEditKey + '"吗?')) { | |||
delete self.dictionaryData[self.currentEditKey]; | |||
self.showMessage('已删除词条,请保存到模块', 'success'); | |||
self.switchTab('list'); | |||
self.renderList(); | |||
} | |||
}); | |||
} | |||
var backBtn = document.getElementById('dict-back-to-list'); | |||
if (backBtn) { | |||
backBtn.addEventListener('click', function() { | |||
self.switchTab('list'); | |||
}); | |||
} | |||
// 变体操作按钮 | |||
document.querySelectorAll('[data-action]').forEach(function(btn) { | |||
btn.addEventListener('click', function() { | |||
var action = this.getAttribute('data-action'); | |||
var index = parseInt(this.getAttribute('data-index')); | |||
if (action === 'edit') { | |||
self.editVariant(index); | |||
} else if (action === 'delete') { | |||
if (confirm('确定要删除这个变体吗?')) { | |||
self.dictionaryData[self.currentEditKey].splice(index, 1); | |||
if (self.dictionaryData[self.currentEditKey].length === 0) { | |||
delete self.dictionaryData[self.currentEditKey]; | |||
self.switchTab('list'); | |||
} | |||
self.renderEditor(); | |||
self.showMessage('已删除变体,请保存到模块', 'success'); | |||
} | |||
} | |||
}); | |||
}); | |||
}, | |||
// 保存新词条 | |||
saveNewEntry: function() { | |||
var name = document.getElementById('dict-entry-name').value.trim(); | |||
var icon = document.getElementById('dict-icon').value.trim(); | |||
var type = document.getElementById('dict-type').getAttribute('data-value'); | |||
if (! | var color = document.getElementById('dict-color').getAttribute('data-value'); | ||
var desc = document.getElementById('dict-desc').value.trim(); | |||
if (!name || !type || !color || !desc) { | |||
this.showMessage('请填写所有必填字段', 'error'); | |||
return; | |||
} | } | ||
dictionaryData[name].push(variant); | |||
} | var variant = { | ||
icon: icon, | |||
类型: type, | |||
颜色: color, | |||
描述: desc | |||
}; | |||
if (!this.dictionaryData[name]) { | |||
this.dictionaryData[name] = []; | |||
} | |||
this.dictionaryData[name].push(variant); | |||
this.showMessage('词条已添加,请保存到模块', 'success'); | |||
this.currentEditKey = name; | |||
this.renderEditor(); | |||
}, | |||
// 显示变体表单 | |||
showVariantForm: function() { | |||
var self = this; | |||
var preview = document.getElementById('dict-preview-container'); | |||
var html = '<h4>添加新变体</h4>'; | |||
html += '<div class="dict-field-row">'; | |||
html += this.renderField('new-icon', 'text', '图标', ''); | |||
html += this.renderField('new-type', 'select', '类型 *', '', this.typeOptions); | |||
html += this.renderField('new-color', 'select', '颜色 *', '', this.colorOptions); | |||
html += '</div>'; | |||
html += this.renderField('new-desc', 'textarea', '描述 *', ''); | |||
html += '<div style="margin-top: 10px;">'; | |||
html += '<div class="dict-button success" id="dict-save-variant">保存变体</div>'; | |||
html += '<div class="dict-button secondary" id="dict-cancel-variant">取消</div>'; | |||
html += '</div>'; | |||
preview.innerHTML = html; | |||
this.initCustomSelects(); | |||
document.getElementById('dict-save-variant').addEventListener('click', function() { | |||
self.saveNewVariant(); | |||
}); | |||
document.getElementById('dict-cancel-variant').addEventListener('click', function() { | |||
preview.innerHTML = ''; | |||
}); | |||
}, | |||
// 保存新变体 | |||
saveNewVariant: function() { | |||
var icon = document.getElementById('dict-new-icon').value.trim(); | |||
} | var type = document.getElementById('dict-new-type').getAttribute('data-value'); | ||
var color = document.getElementById('dict-new-color').getAttribute('data-value'); | |||
var desc = document.getElementById('dict-new-desc').value.trim(); | |||
if (!type || !color || !desc) { | |||
this.showMessage('请填写所有必填字段', 'error'); | |||
return; | |||
} | |||
var variant = { | |||
icon: icon, | |||
类型: type, | |||
颜色: color, | |||
描述: desc | |||
}; | |||
this.dictionaryData[this.currentEditKey].push(variant); | |||
this.showMessage('变体已添加,请保存到模块', 'success'); | |||
this.renderEditor(); | |||
}, | |||
// 编辑变体 | |||
editVariant: function(index) { | |||
var self = this; | |||
var variant = this.dictionaryData[this.currentEditKey][index]; | |||
var preview = document.getElementById('dict-preview-container'); | |||
var html = '<h4>编辑变体</h4>'; | |||
html += '<div class="dict-field-row">'; | |||
html += this.renderField('edit-icon', 'text', '图标', variant.icon); | |||
html += this.renderField('edit-type', 'select', '类型 *', variant.类型, this.typeOptions); | |||
html += this.renderField('edit-color', 'select', '颜色 *', variant.颜色, this.colorOptions); | |||
html += '</div>'; | |||
html += this.renderField('edit-desc', 'textarea', '描述 *', variant.描述); | |||
html += '<div style="margin-top: 10px;">'; | |||
html += '<div class="dict-button success" id="dict-update-variant" data-index="' + index + '">更新变体</div>'; | |||
html += '<div class="dict-button secondary" id="dict-cancel-edit-variant">取消</div>'; | |||
html += '</div>'; | |||
preview.innerHTML = html; | |||
this.initCustomSelects(); | |||
document.getElementById('dict-update-variant').addEventListener('click', function() { | |||
var idx = parseInt(this.getAttribute('data-index')); | |||
self.updateVariant(idx); | |||
}); | |||
document.getElementById('dict-cancel-edit-variant').addEventListener('click', function() { | |||
preview.innerHTML = ''; | |||
}); | |||
}, | |||
// 更新变体 | |||
updateVariant: function(index) { | |||
var icon = document.getElementById('dict-edit-icon').value.trim(); | |||
var type = document.getElementById('dict-edit-type').getAttribute('data-value'); | |||
var color = document.getElementById('dict-edit-color').getAttribute('data-value'); | |||
var desc = document.getElementById('dict-edit-desc').value.trim(); | |||
if (!type || !color || !desc) { | |||
this.showMessage('请填写所有必填字段', 'error'); | |||
return; | |||
} | |||
this.dictionaryData[this.currentEditKey][index] = { | |||
icon: icon, | |||
类型: type, | |||
颜色: color, | |||
描述: desc | |||
}; | |||
this.showMessage('变体已更新,请保存到模块', 'success'); | |||
this.renderEditor(); | |||
}, | |||
// 保存到模块 | |||
saveToModule: function() { | |||
// | var self = this; | ||
if (!confirm('确定要保存到模块吗?这将覆盖现有数据!')) { | |||
return; | |||
} | |||
var luaContent = this.generateLuaContent(); | |||
this.showMessage('保存中...', 'info'); | |||
this.api.postWithToken('csrf', { | |||
action: 'edit', | |||
title: this.MODULE_PAGE, | |||
text: luaContent, | |||
summary: '通过词典管理器更新', | |||
format: 'json' | |||
}).done(function() { | |||
self.showMessage('保存成功!', 'success'); | |||
}).fail(function(code, error) { | |||
console.error('保存失败:', code, error); | |||
self.showMessage('保存失败: ' + (error.error ? error.error.info : '未知错误'), 'error'); | |||
}); | }); | ||
} | }, | ||
// 生成Lua内容 | |||
generateLuaContent: function() { | |||
var lua = 'local data = {}\n\ndata.dictionary = {\n'; | |||
var entries = Object.keys(this.dictionaryData).sort(); | |||
entries.forEach(function(key) { | |||
var variants = this.dictionaryData[key]; | |||
lua += ' | lua += ' ["' + key + '"] = {\n'; | ||
}); | |||
lua += ' | variants.forEach(function(variant) { | ||
} | lua += ' {\n'; | ||
lua += ' ["icon"] = "' + (variant.icon || '') + '",\n'; | |||
lua += ' ["类型"] = "' + variant.类型 + '",\n'; | |||
lua += ' ["颜色"] = "' + variant.颜色 + '",\n'; | |||
lua += ' ["描述"] = "' + variant.描述 + '",\n'; | |||
lua += ' },\n'; | |||
}); | |||
lua += ' },\n'; | |||
}, this); | |||
lua += '}\n\nreturn data\n'; | |||
return lua; | |||
}, | |||
// 获取颜色类名 | |||
getColorClass: function(color) { | |||
var colorMap = { | |||
'白': 'dict-badge-white', | |||
'蓝': 'dict-badge-blue', | |||
'红': 'dict-badge-red', | |||
'橙': 'dict-badge-orange', | |||
'彩': 'dict-badge-rainbow' | |||
}; | |||
return colorMap[color] || 'dict-badge-white'; | |||
}, | |||
if (type === 'success' || type === 'error') { | // 显示消息 | ||
showMessage: function(message, type) { | |||
var container = document.getElementById('dict-message'); | |||
container.innerHTML = '<div class="dict-message ' + type + '">' + mw.html.escape(message) + '</div>'; | |||
} | |||
if (type === 'success' || type === 'error') { | |||
setTimeout(function() { | |||
container.innerHTML = ''; | |||
}, 5000); | |||
} | |||
} | } | ||
} | }; | ||
// 页面加载完成后初始化 | // 页面加载完成后初始化 | ||
$(function() { | |||
DictManager.init(); | |||
} | }); | ||
})(); | })(); | ||
2025年10月3日 (五) 19:21的版本
/**
* MediaWiki词典编辑器
* 用于管理模块:词典/data中的词条数据
*/
(function() {
'use strict';
// 只在MediaWiki:Dictionary页面运行
if (mw.config.get('wgPageName') !== 'MediaWiki:Dictionary') {
return;
}
var DictManager = {
api: new mw.Api(),
MODULE_PAGE: '模块:词典/data',
dictionaryData: {},
currentEditKey: null,
currentEditIndex: null,
// 类型选项
typeOptions: ['', '卡牌机制', '战斗员专属机制', 'buff', 'debuff'],
colorOptions: ['', '白', '蓝', '红', '橙', '彩'],
// 初始化
init: function() {
this.createUI();
this.loadData();
},
// 创建UI
createUI: function() {
var container = document.createElement('div');
container.className = 'dict-editor';
container.innerHTML = `
<div class="dict-section">
<h3>词典管理器</h3>
<div id="dict-message"></div>
<div class="dict-tabs">
<div class="dict-tab active" data-tab="list">词条列表</div>
<div class="dict-tab" data-tab="edit">编辑/新建</div>
</div>
<div id="tab-list" class="dict-tab-content active">
<div class="dict-button success" id="dict-create-new">新建词条</div>
<div class="dict-button" id="dict-refresh">刷新数据</div>
<div class="dict-button secondary" id="dict-save-module">保存到模块</div>
<div id="dict-list-container" class="dict-loading">加载中...</div>
</div>
<div id="tab-edit" class="dict-tab-content">
<div id="dict-editor-container"></div>
</div>
</div>
`;
var content = document.getElementById('mw-content-text');
content.innerHTML = '';
content.appendChild(container);
this.bindEvents();
},
// 绑定事件
bindEvents: function() {
var self = this;
// 标签切换
document.querySelectorAll('.dict-tab').forEach(function(tab) {
tab.addEventListener('click', function() {
self.switchTab(this.getAttribute('data-tab'));
});
});
// 新建词条
document.getElementById('dict-create-new').addEventListener('click', function() {
self.createNew();
});
// 刷新数据
document.getElementById('dict-refresh').addEventListener('click', function() {
self.loadData();
});
// 保存到模块
document.getElementById('dict-save-module').addEventListener('click', function() {
self.saveToModule();
});
},
// 切换标签
switchTab: function(tabName) {
document.querySelectorAll('.dict-tab').forEach(function(tab) {
tab.classList.remove('active');
});
document.querySelectorAll('.dict-tab-content').forEach(function(content) {
content.classList.remove('active');
});
document.querySelector('[data-tab="' + tabName + '"]').classList.add('active');
document.getElementById('tab-' + tabName).classList.add('active');
},
// 加载数据
loadData: function() {
var self = this;
self.showMessage('加载中...', 'info');
this.api.get({
action: 'query',
prop: 'revisions',
titles: this.MODULE_PAGE,
rvprop: 'content',
rvslots: 'main',
format: 'json'
}).done(function(data) {
var pages = data.query.pages;
var pageId = Object.keys(pages)[0];
if (pageId === '-1') {
self.showMessage('模块页面不存在', 'error');
return;
}
var content = pages[pageId].revisions[0].slots.main['*'];
self.parseModuleData(content);
self.renderList();
self.showMessage('数据加载成功', 'success');
}).fail(function() {
self.showMessage('加载失败', 'error');
});
},
// 解析模块数据
parseModuleData: function(content) {
try {
var match = content.match(/data\.dictionary\s*=\s*\{([\s\S]*?)\n\}/);
if (!match) {
this.dictionaryData = {};
return;
}
var dictContent = match[1];
this.dictionaryData = {};
// 使用正则匹配每个词条
var entryRegex = /$$"([^"]+)"$$\s*=\s*\{([\s\S]*?)\n\s{4}\}/g;
var entryMatch;
while ((entryMatch = entryRegex.exec(dictContent)) !== null) {
var key = entryMatch[1];
var variantsContent = entryMatch[2];
this.dictionaryData[key] = [];
// 匹配每个变体
var variantRegex = /\{[\s\S]*?$$"icon"$$\s*=\s*"([^"]*)"[\s\S]*?$$"类型"$$\s*=\s*"([^"]*)"[\s\S]*?$$"颜色"$$\s*=\s*"([^"]*)"[\s\S]*?$$"描述"$$\s*=\s*"([^"]*)"[\s\S]*?\}/g;
var variantMatch;
while ((variantMatch = variantRegex.exec(variantsContent)) !== null) {
this.dictionaryData[key].push({
icon: variantMatch[1],
类型: variantMatch[2],
颜色: variantMatch[3],
描述: variantMatch[4]
});
}
}
console.log('解析完成:', this.dictionaryData);
} catch (e) {
console.error('解析错误:', e);
this.dictionaryData = {};
}
},
// 渲染列表
renderList: function() {
var container = document.getElementById('dict-list-container');
if (Object.keys(this.dictionaryData).length === 0) {
container.innerHTML = '<div class="dict-message info">暂无词条,点击"新建词条"开始创建</div>';
return;
}
var html = '<div class="dict-grid">';
for (var key in this.dictionaryData) {
var variants = this.dictionaryData[key];
html += '<div class="dict-list-item" data-key="' + mw.html.escape(key) + '">';
html += '<strong>' + mw.html.escape(key) + '</strong>';
html += '<div style="margin-top: 5px; font-size: 12px; color: #72777d;">';
html += variants.length + ' 个变体';
html += '</div>';
html += '</div>';
}
html += '</div>';
container.innerHTML = html;
var self = this;
document.querySelectorAll('.dict-list-item').forEach(function(item) {
item.addEventListener('click', function() {
var key = this.getAttribute('data-key');
self.editEntry(key);
});
});
},
// 新建词条
createNew: function() {
this.currentEditKey = null;
this.currentEditIndex = null;
this.switchTab('edit');
this.renderEditor();
this.showMessage('请填写词条信息', 'info');
},
// 编辑词条
editEntry: function(key) {
this.currentEditKey = key;
this.switchTab('edit');
this.renderEditor();
},
// 渲染编辑器
renderEditor: function() {
var self = this;
var container = document.getElementById('dict-editor-container');
var html = '<h4>' + (this.currentEditKey ? '编辑词条: ' + mw.html.escape(this.currentEditKey) : '新建词条') + '</h4>';
if (!this.currentEditKey) {
// 新建模式
html += '<div class="dict-form-group">';
html += '<label>词条名称 *</label>';
html += '<input type="text" class="dict-input" id="dict-entry-name" placeholder="例如: 粉碎">';
html += '</div>';
html += '<h4>变体信息</h4>';
html += '<div class="dict-field-row">';
html += this.renderField('icon', 'text', '图标', '');
html += this.renderField('type', 'select', '类型 *', '', this.typeOptions);
html += this.renderField('color', 'select', '颜色 *', '', this.colorOptions);
html += '</div>';
html += this.renderField('desc', 'textarea', '描述 *', '');
html += '<div style="margin-top: 20px;">';
html += '<div class="dict-button success" id="dict-save-new">保存词条</div>';
html += '<div class="dict-button secondary" id="dict-cancel-edit">取消</div>';
html += '</div>';
} else {
// 编辑模式 - 显示所有变体
var variants = this.dictionaryData[this.currentEditKey];
html += '<div style="margin-bottom: 20px;">';
html += '<div class="dict-button success" id="dict-add-variant">添加新变体</div>';
html += '<div class="dict-button danger" id="dict-delete-entry">删除整个词条</div>';
html += '<div class="dict-button secondary" id="dict-back-to-list">返回列表</div>';
html += '</div>';
html += '<h4>现有变体</h4>';
variants.forEach(function(variant, index) {
var colorClass = self.getColorClass(variant.颜色);
html += '<div class="dict-variant" data-index="' + index + '">';
html += '<div class="dict-variant-header">';
html += '<span class="dict-badge ' + colorClass + '">' + mw.html.escape(variant.类型) + '</span>';
html += '<span class="dict-badge ' + colorClass + '">' + mw.html.escape(variant.颜色) + '</span>';
html += '<div class="dict-button" style="float: right; margin-left: 5px;" data-action="delete" data-index="' + index + '">删除</div>';
html += '<div class="dict-button" style="float: right;" data-action="edit" data-index="' + index + '">编辑</div>';
html += '</div>';
html += '<div class="dict-variant-desc">' + mw.html.escape(variant.描述) + '</div>';
if (variant.icon) {
html += '<div class="dict-variant-icon">图标: ' + mw.html.escape(variant.icon) + '</div>';
}
html += '</div>';
});
}
html += '<div id="dict-preview-container"></div>';
container.innerHTML = html;
this.initCustomSelects();
this.bindEditorEvents();
},
// 渲染表单字段
renderField: function(id, type, label, value, options) {
var html = '<div class="dict-form-group">';
html += '<label>' + mw.html.escape(label) + '</label>';
if (type === 'select') {
html += '<div class="dict-custom-select" id="dict-' + id + '" data-value="' + mw.html.escape(value) + '">';
html += '<div class="dict-select-display">' + (value || '请选择') + '</div>';
html += '<div class="dict-select-options">';
options.forEach(function(opt) {
html += '<div class="dict-select-option" data-value="' + mw.html.escape(opt) + '">' +
mw.html.escape(opt || '请选择') + '</div>';
});
html += '</div></div>';
} else if (type === 'textarea') {
html += '<textarea class="dict-textarea" id="dict-' + id + '">' + mw.html.escape(value) + '</textarea>';
} else {
html += '<input type="text" class="dict-input" id="dict-' + id + '" value="' + mw.html.escape(value) + '">';
}
html += '</div>';
return html;
},
// 初始化自定义选择器
initCustomSelects: function() {
var self = this;
document.querySelectorAll('.dict-custom-select').forEach(function(select) {
var display = select.querySelector('.dict-select-display');
display.addEventListener('click', function(e) {
e.stopPropagation();
// 关闭其他选择器
document.querySelectorAll('.dict-custom-select').forEach(function(s) {
if (s !== select) s.classList.remove('open');
});
select.classList.toggle('open');
});
select.querySelectorAll('.dict-select-option').forEach(function(option) {
option.addEventListener('click', function(e) {
e.stopPropagation();
var value = this.getAttribute('data-value');
select.setAttribute('data-value', value);
display.textContent = this.textContent;
select.classList.remove('open');
});
});
});
// 点击外部关闭
document.addEventListener('click', function() {
document.querySelectorAll('.dict-custom-select').forEach(function(s) {
s.classList.remove('open');
});
});
},
// 绑定编辑器事件
bindEditorEvents: function() {
var self = this;
var saveBtn = document.getElementById('dict-save-new');
if (saveBtn) {
saveBtn.addEventListener('click', function() {
self.saveNewEntry();
});
}
var cancelBtn = document.getElementById('dict-cancel-edit');
if (cancelBtn) {
cancelBtn.addEventListener('click', function() {
self.switchTab('list');
});
}
var addVariantBtn = document.getElementById('dict-add-variant');
if (addVariantBtn) {
addVariantBtn.addEventListener('click', function() {
self.showVariantForm();
});
}
var deleteEntryBtn = document.getElementById('dict-delete-entry');
if (deleteEntryBtn) {
deleteEntryBtn.addEventListener('click', function() {
if (confirm('确定要删除整个词条"' + self.currentEditKey + '"吗?')) {
delete self.dictionaryData[self.currentEditKey];
self.showMessage('已删除词条,请保存到模块', 'success');
self.switchTab('list');
self.renderList();
}
});
}
var backBtn = document.getElementById('dict-back-to-list');
if (backBtn) {
backBtn.addEventListener('click', function() {
self.switchTab('list');
});
}
// 变体操作按钮
document.querySelectorAll('[data-action]').forEach(function(btn) {
btn.addEventListener('click', function() {
var action = this.getAttribute('data-action');
var index = parseInt(this.getAttribute('data-index'));
if (action === 'edit') {
self.editVariant(index);
} else if (action === 'delete') {
if (confirm('确定要删除这个变体吗?')) {
self.dictionaryData[self.currentEditKey].splice(index, 1);
if (self.dictionaryData[self.currentEditKey].length === 0) {
delete self.dictionaryData[self.currentEditKey];
self.switchTab('list');
}
self.renderEditor();
self.showMessage('已删除变体,请保存到模块', 'success');
}
}
});
});
},
// 保存新词条
saveNewEntry: function() {
var name = document.getElementById('dict-entry-name').value.trim();
var icon = document.getElementById('dict-icon').value.trim();
var type = document.getElementById('dict-type').getAttribute('data-value');
var color = document.getElementById('dict-color').getAttribute('data-value');
var desc = document.getElementById('dict-desc').value.trim();
if (!name || !type || !color || !desc) {
this.showMessage('请填写所有必填字段', 'error');
return;
}
var variant = {
icon: icon,
类型: type,
颜色: color,
描述: desc
};
if (!this.dictionaryData[name]) {
this.dictionaryData[name] = [];
}
this.dictionaryData[name].push(variant);
this.showMessage('词条已添加,请保存到模块', 'success');
this.currentEditKey = name;
this.renderEditor();
},
// 显示变体表单
showVariantForm: function() {
var self = this;
var preview = document.getElementById('dict-preview-container');
var html = '<h4>添加新变体</h4>';
html += '<div class="dict-field-row">';
html += this.renderField('new-icon', 'text', '图标', '');
html += this.renderField('new-type', 'select', '类型 *', '', this.typeOptions);
html += this.renderField('new-color', 'select', '颜色 *', '', this.colorOptions);
html += '</div>';
html += this.renderField('new-desc', 'textarea', '描述 *', '');
html += '<div style="margin-top: 10px;">';
html += '<div class="dict-button success" id="dict-save-variant">保存变体</div>';
html += '<div class="dict-button secondary" id="dict-cancel-variant">取消</div>';
html += '</div>';
preview.innerHTML = html;
this.initCustomSelects();
document.getElementById('dict-save-variant').addEventListener('click', function() {
self.saveNewVariant();
});
document.getElementById('dict-cancel-variant').addEventListener('click', function() {
preview.innerHTML = '';
});
},
// 保存新变体
saveNewVariant: function() {
var icon = document.getElementById('dict-new-icon').value.trim();
var type = document.getElementById('dict-new-type').getAttribute('data-value');
var color = document.getElementById('dict-new-color').getAttribute('data-value');
var desc = document.getElementById('dict-new-desc').value.trim();
if (!type || !color || !desc) {
this.showMessage('请填写所有必填字段', 'error');
return;
}
var variant = {
icon: icon,
类型: type,
颜色: color,
描述: desc
};
this.dictionaryData[this.currentEditKey].push(variant);
this.showMessage('变体已添加,请保存到模块', 'success');
this.renderEditor();
},
// 编辑变体
editVariant: function(index) {
var self = this;
var variant = this.dictionaryData[this.currentEditKey][index];
var preview = document.getElementById('dict-preview-container');
var html = '<h4>编辑变体</h4>';
html += '<div class="dict-field-row">';
html += this.renderField('edit-icon', 'text', '图标', variant.icon);
html += this.renderField('edit-type', 'select', '类型 *', variant.类型, this.typeOptions);
html += this.renderField('edit-color', 'select', '颜色 *', variant.颜色, this.colorOptions);
html += '</div>';
html += this.renderField('edit-desc', 'textarea', '描述 *', variant.描述);
html += '<div style="margin-top: 10px;">';
html += '<div class="dict-button success" id="dict-update-variant" data-index="' + index + '">更新变体</div>';
html += '<div class="dict-button secondary" id="dict-cancel-edit-variant">取消</div>';
html += '</div>';
preview.innerHTML = html;
this.initCustomSelects();
document.getElementById('dict-update-variant').addEventListener('click', function() {
var idx = parseInt(this.getAttribute('data-index'));
self.updateVariant(idx);
});
document.getElementById('dict-cancel-edit-variant').addEventListener('click', function() {
preview.innerHTML = '';
});
},
// 更新变体
updateVariant: function(index) {
var icon = document.getElementById('dict-edit-icon').value.trim();
var type = document.getElementById('dict-edit-type').getAttribute('data-value');
var color = document.getElementById('dict-edit-color').getAttribute('data-value');
var desc = document.getElementById('dict-edit-desc').value.trim();
if (!type || !color || !desc) {
this.showMessage('请填写所有必填字段', 'error');
return;
}
this.dictionaryData[this.currentEditKey][index] = {
icon: icon,
类型: type,
颜色: color,
描述: desc
};
this.showMessage('变体已更新,请保存到模块', 'success');
this.renderEditor();
},
// 保存到模块
saveToModule: function() {
var self = this;
if (!confirm('确定要保存到模块吗?这将覆盖现有数据!')) {
return;
}
var luaContent = this.generateLuaContent();
this.showMessage('保存中...', 'info');
this.api.postWithToken('csrf', {
action: 'edit',
title: this.MODULE_PAGE,
text: luaContent,
summary: '通过词典管理器更新',
format: 'json'
}).done(function() {
self.showMessage('保存成功!', 'success');
}).fail(function(code, error) {
console.error('保存失败:', code, error);
self.showMessage('保存失败: ' + (error.error ? error.error.info : '未知错误'), 'error');
});
},
// 生成Lua内容
generateLuaContent: function() {
var lua = 'local data = {}\n\ndata.dictionary = {\n';
var entries = Object.keys(this.dictionaryData).sort();
entries.forEach(function(key) {
var variants = this.dictionaryData[key];
lua += ' ["' + key + '"] = {\n';
variants.forEach(function(variant) {
lua += ' {\n';
lua += ' ["icon"] = "' + (variant.icon || '') + '",\n';
lua += ' ["类型"] = "' + variant.类型 + '",\n';
lua += ' ["颜色"] = "' + variant.颜色 + '",\n';
lua += ' ["描述"] = "' + variant.描述 + '",\n';
lua += ' },\n';
});
lua += ' },\n';
}, this);
lua += '}\n\nreturn data\n';
return lua;
},
// 获取颜色类名
getColorClass: function(color) {
var colorMap = {
'白': 'dict-badge-white',
'蓝': 'dict-badge-blue',
'红': 'dict-badge-red',
'橙': 'dict-badge-orange',
'彩': 'dict-badge-rainbow'
};
return colorMap[color] || 'dict-badge-white';
},
// 显示消息
showMessage: function(message, type) {
var container = document.getElementById('dict-message');
container.innerHTML = '<div class="dict-message ' + type + '">' + mw.html.escape(message) + '</div>';
if (type === 'success' || type === 'error') {
setTimeout(function() {
container.innerHTML = '';
}, 5000);
}
}
};
// 页面加载完成后初始化
$(function() {
DictManager.init();
});
})();