卡厄思
梦
境
菜单
首页
回到首页
WIKI工具
全站样式
全站JS
修改导航栏
测试
沙盒
可视化管理器
战斗员管理器
卡牌管理器
伙伴管理器
装备管理器
词典管理器
图鉴
战斗员
伙伴
装备
怪物卡牌
中立卡牌
词典
小工具
配队模拟器
节奏榜生成器
搜索
链入页面
相关更改
特殊页面
页面信息
最近更改
登录
MediaWiki
查看“︁Card.js”︁的源代码
←
MediaWiki:Card.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。 如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
(function() { 'use strict'; // 加载CSS mw.loader.load('/index.php?title=Mediawiki:Card.css&action=raw&ctype=text/css', 'text/css'); // 卡牌管理器类 class CardManager { constructor() { this.currentFighter = ''; this.cards = {}; this.currentCard = null; this.fighters = []; // 默认数据 this.defaultData = { order: [], ego: '' }; // 当前编辑的卡牌数据 this.cardData = { name: '', displayname: '', art: '', group: '', rarity: '', god: '', ap: '', type: '攻击', dict: '', desc_global: '', sub: '', isinspiration: false, isgod_inspiration: false, inspirations: [], god_inspirations: { circen: [], diallos: [], nihilum: [], secred: [], vitor: [] } }; } // 初始化 async init() { await this.loadFighters(); this.render(); this.bindEvents(); } // 加载战斗员列表 async loadFighters() { try { const api = new mw.Api(); const response = await api.get({ action: 'query', list: 'categorymembers', cmtitle: 'Category:战斗员', cmlimit: 500 }); this.fighters = response.query.categorymembers.map(page => page.title); } catch (error) { console.error('加载战斗员列表失败:', error); this.fighters = []; } } // 渲染主界面 render() { const container = this.createDiv('card-manager'); // 左侧面板 const leftPanel = this.createDiv('card-input-panel'); leftPanel.appendChild(this.renderFighterSelect()); leftPanel.appendChild(this.renderDefaultInfo()); leftPanel.appendChild(this.renderCardInput()); // 中间面板 const middlePanel = this.createDiv('card-list-panel'); middlePanel.appendChild(this.renderCardLists()); // 右侧面板 const rightPanel = this.createDiv('card-preview-panel'); rightPanel.appendChild(this.renderPreview()); container.appendChild(leftPanel); container.appendChild(middlePanel); container.appendChild(rightPanel); // 添加到页面 const content = document.getElementById('mw-content-text'); if (content) { content.innerHTML = ''; content.appendChild(container); } } // 创建div元素 createDiv(className, text = '') { const div = document.createElement('div'); if (className) div.className = className; if (text) div.textContent = text; return div; } // 渲染战斗员选择 renderFighterSelect() { const container = this.createDiv('form-group'); const label = this.createDiv('form-label', '当前战斗员'); container.appendChild(label); const select = this.createCustomSelect( this.fighters, this.currentFighter, (value) => { this.currentFighter = value; this.loadFighterData(); } ); container.appendChild(select); return container; } // 渲染默认信息区 renderDefaultInfo() { const container = this.createDiv('default-info-section'); const title = this.createDiv('section-title', '默认信息'); container.appendChild(title); // 卡牌顺序 const orderGroup = this.createDiv('form-group'); const orderLabel = this.createDiv('form-label', '卡牌顺序(card.order)'); const orderInput = this.createInput('text', this.defaultData.order.join(','), (value) => { this.defaultData.order = value.split(',').map(s => s.trim()).filter(s => s); this.updatePreview(); }); orderGroup.appendChild(orderLabel); orderGroup.appendChild(orderInput); container.appendChild(orderGroup); // 属性 const egoGroup = this.createDiv('form-group'); const egoLabel = this.createDiv('form-label', '属性(ego)'); const egoInput = this.createInput('text', this.defaultData.ego, (value) => { this.defaultData.ego = value; this.updatePreview(); }); egoGroup.appendChild(egoLabel); egoGroup.appendChild(egoInput); container.appendChild(egoGroup); return container; } // 渲染卡牌输入区 renderCardInput() { const container = this.createDiv(); const title = this.createDiv('section-title', '卡牌数据'); container.appendChild(title); // 卡牌名称 container.appendChild(this.createFormGroup('卡牌名称', this.createInput('text', this.cardData.name, (value) => { this.cardData.name = value; this.updatePreview(); }) )); // 显示名称 container.appendChild(this.createFormGroup('显示名称(displayname)', this.createInput('text', this.cardData.displayname, (value) => { this.cardData.displayname = value; this.updatePreview(); }) )); // 图片 container.appendChild(this.createFormGroup('图片(art)', this.createInput('text', this.cardData.art, (value) => { this.cardData.art = value; this.updatePreview(); }) )); // 卡组 container.appendChild(this.createFormGroup('卡组(group)', this.createGroupSelect() )); // 稀有度 container.appendChild(this.createFormGroup('稀有度(rarity)', this.createRaritySelect() )); // 神明 container.appendChild(this.createFormGroup('神明', this.createGodSelect() )); // AP container.appendChild(this.createFormGroup('AP', this.createInput('text', this.cardData.ap, (value) => { this.cardData.ap = value; this.updatePreview(); }) )); // 卡牌类型 container.appendChild(this.createFormGroup('卡牌类型(type)', this.createTypeSelect() )); // 机制 container.appendChild(this.createFormGroup('机制(dict)', this.createInput('text', this.cardData.dict, (value) => { this.cardData.dict = value; this.updatePreview(); }) )); // 描述 const descGroup = this.createDiv('form-group'); const descLabel = this.createDiv('form-label', '描述(desc_global)'); descGroup.appendChild(descLabel); descGroup.appendChild(this.createFormatButtons()); descGroup.appendChild(this.createTextarea(this.cardData.desc_global, (value) => { this.cardData.desc_global = value; this.updatePreview(); })); container.appendChild(descGroup); // 衍生卡牌 container.appendChild(this.createFormGroup('衍生卡牌(sub)', this.createInput('text', this.cardData.sub, (value) => { this.cardData.sub = value; this.updatePreview(); }) )); // 是否存在灵光一闪 container.appendChild(this.createFormGroup('是否存在灵光一闪', this.createCheckbox(this.cardData.isinspiration, (checked) => { this.cardData.isinspiration = checked; this.updatePreview(); }) )); // 是否存在神光一闪 container.appendChild(this.createFormGroup('是否存在神光一闪', this.createCheckbox(this.cardData.isgod_inspiration, (checked) => { this.cardData.isgod_inspiration = checked; this.updatePreview(); }) )); // 按钮组 const btnGroup = this.createDiv('btn-group'); const saveBtn = this.createDiv('btn btn-primary', '保存卡牌'); saveBtn.onclick = () => this.saveCard(); const newBtn = this.createDiv('btn btn-success', '新建卡牌'); newBtn.onclick = () => this.newCard(); btnGroup.appendChild(saveBtn); btnGroup.appendChild(newBtn); container.appendChild(btnGroup); return container; } // 创建表单组 createFormGroup(label, input) { const group = this.createDiv('form-group'); const labelDiv = this.createDiv('form-label', label); group.appendChild(labelDiv); group.appendChild(input); return group; } // 创建自定义下拉框 createCustomSelect(options, selected, onChange) { const container = this.createDiv('custom-select'); const display = this.createDiv('select-display', selected || '请选择...'); const arrow = this.createDiv('select-arrow', '▼'); display.appendChild(arrow); const dropdown = this.createDiv('select-dropdown'); options.forEach(option => { const optionDiv = this.createDiv('select-option', option); if (option === selected) { optionDiv.classList.add('selected'); } optionDiv.onclick = () => { display.childNodes[0].textContent = option; dropdown.querySelectorAll('.select-option').forEach(o => o.classList.remove('selected')); optionDiv.classList.add('selected'); dropdown.classList.remove('active'); onChange(option); }; dropdown.appendChild(optionDiv); }); display.onclick = () => { dropdown.classList.toggle('active'); }; // 点击外部关闭 document.addEventListener('click', (e) => { if (!container.contains(e.target)) { dropdown.classList.remove('active'); } }); container.appendChild(display); container.appendChild(dropdown); return container; } // 创建输入框 createInput(type, value, onChange) { const input = this.createDiv('custom-input'); input.contentEditable = true; input.textContent = value; input.oninput = () => onChange(input.textContent); return input; } // 创建文本域 createTextarea(value, onChange) { const textarea = this.createDiv('custom-textarea'); textarea.contentEditable = true; textarea.innerHTML = value.replace(/<br>/g, '\n'); textarea.oninput = () => onChange(textarea.textContent); return textarea; } // 创建格式化按钮 createFormatButtons() { const container = this.createDiv('format-buttons'); const buttons = [ { label: '蓝色文本', class: 'blue', template: '{{文本|蓝|%s}}' }, { label: '绿色文本', class: 'green', template: '{{文本|绿|%s}}' }, { label: '绿色描边', class: 'green', template: '{{描边|绿|%s}}' }, { label: '词典', class: '', template: '{{词典|%s}}' }, { label: '换行', class: '', template: '<br>' } ]; buttons.forEach(btn => { const button = this.createDiv(`format-btn ${btn.class}`, btn.label); button.onclick = () => { const textarea = button.parentElement.nextElementSibling; this.insertTemplate(textarea, btn.template); }; container.appendChild(button); }); return container; } // 插入模板 insertTemplate(textarea, template) { const selection = window.getSelection(); const selectedText = selection.toString(); if (template === '<br>') { const text = textarea.textContent; const pos = this.getCaretPosition(textarea); textarea.textContent = text.slice(0, pos) + '\n' + text.slice(pos); } else { const result = template.replace('%s', selectedText || '选择文字'); if (selectedText) { document.execCommand('insertText', false, result); } else { const text = textarea.textContent; const pos = this.getCaretPosition(textarea); textarea.textContent = text.slice(0, pos) + result + text.slice(pos); } } textarea.dispatchEvent(new Event('input')); } // 获取光标位置 getCaretPosition(element) { const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); const preCaretRange = range.cloneRange(); preCaretRange.selectNodeContents(element); preCaretRange.setEnd(range.endContainer, range.endOffset); return preCaretRange.toString().length; } return 0; } // 创建复选框 createCheckbox(checked, onChange) { const container = this.createDiv('checkbox-group'); const checkbox = this.createDiv('custom-checkbox'); if (checked) checkbox.classList.add('checked'); const label = this.createDiv('', '是'); checkbox.onclick = () => { checkbox.classList.toggle('checked'); const isChecked = checkbox.classList.contains('checked'); label.textContent = isChecked ? '是' : '否'; onChange(isChecked); }; container.appendChild(checkbox); container.appendChild(label); return container; } // 创建卡组选择 createGroupSelect() { const container = this.createDiv('group-options'); const groups = ['自我意识技能', '起始卡牌', '独特卡牌', '灵光一闪', '神光一闪']; groups.forEach(group => { const option = this.createDiv('group-option', group); if (this.cardData.group === group) { option.classList.add('selected'); } option.onclick = () => { container.querySelectorAll('.group-option').forEach(o => o.classList.remove('selected')); option.classList.add('selected'); this.cardData.group = group; this.updatePreview(); }; container.appendChild(option); }); return container; } // 创建稀有度选择 createRaritySelect() { const container = this.createDiv('rarity-options'); const rarities = ['白', '蓝', '橙', '彩']; rarities.forEach(rarity => { const option = this.createDiv('rarity-option', rarity); if (this.cardData.rarity === rarity) { option.classList.add('selected'); } option.onclick = () => { container.querySelectorAll('.rarity-option').forEach(o => o.classList.remove('selected')); option.classList.add('selected'); this.cardData.rarity = rarity; this.updatePreview(); }; container.appendChild(option); }); return container; } // 创建神明选择 createGodSelect() { const container = this.createDiv('god-options'); const gods = ['circen', 'diallos', 'nihilum', 'secred', 'vitor']; gods.forEach(god => { const option = this.createDiv('god-option', god); if (this.cardData.god === god) { option.classList.add('selected'); } option.onclick = () => { container.querySelectorAll('.god-option').forEach(o => o.classList.remove('selected')); option.classList.add('selected'); this.cardData.god = god; this.updatePreview(); }; container.appendChild(option); }); return container; } // 创建类型选择 createTypeSelect() { const container = this.createDiv('type-options'); const types = ['攻击', '技能', '强化']; types.forEach(type => { const option = this.createDiv('type-option', type); if (this.cardData.type === type) { option.classList.add('selected'); } option.onclick = () => { container.querySelectorAll('.type-option').forEach(o => o.classList.remove('selected')); option.classList.add('selected'); this.cardData.type = type; this.updatePreview(); }; container.appendChild(option); }); return container; } // 渲染卡牌列表 renderCardLists() { const container = this.createDiv(); // 卡牌列表 const cardListTitle = this.createDiv('panel-title', '卡牌列表'); container.appendChild(cardListTitle); const cardListContainer = this.createDiv('list-container'); cardListContainer.id = 'card-list'; this.updateCardList(cardListContainer); container.appendChild(cardListContainer); return container; } // 更新卡牌列表 updateCardList(container) { container.innerHTML = ''; if (Object.keys(this.cards).length === 0) { container.appendChild(this.createDiv('list-empty', '暂无卡牌')); return; } Object.keys(this.cards).forEach(name => { const card = this.cards[name]; const item = this.createDiv('card-list-item'); const info = this.createDiv(); const nameDiv = this.createDiv('card-list-item-name', name); const detailDiv = this.createDiv('card-list-item-info', `${card.type || '攻击'} | AP:${card.ap || 0} | ${card.rarity || ''}` ); info.appendChild(nameDiv); info.appendChild(detailDiv); const deleteBtn = this.createDiv('delete-btn', '删除'); deleteBtn.onclick = (e) => { e.stopPropagation(); if (confirm(`确定要删除卡牌"${name}"吗?`)) { delete this.cards[name]; this.updateCardList(container); this.updatePreview(); // 如果删除的是当前编辑的卡牌,清空表单 if (this.currentCard === name) { this.newCard(); } } }; item.appendChild(info); item.appendChild(deleteBtn); item.onclick = () => { this.loadCard(name); container.querySelectorAll('.card-list-item').forEach(i => i.classList.remove('active')); item.classList.add('active'); }; container.appendChild(item); }); } // 渲染预览 renderPreview() { const container = this.createDiv(); const title = this.createDiv('panel-title', 'Lua代码预览'); container.appendChild(title); const preview = this.createDiv('preview-code'); preview.id = 'code-preview'; container.appendChild(preview); this.updatePreview(); // 添加复制按钮 const copyBtn = this.createDiv('btn btn-primary', '复制代码'); copyBtn.style.marginTop = '10px'; copyBtn.onclick = () => this.copyCode(); container.appendChild(copyBtn); return container; } // 更新预览 updatePreview() { const preview = document.getElementById('code-preview'); if (!preview) return; preview.textContent = this.generateLuaCode(); } // 生成Lua代码 generateLuaCode() { let code = 'local card = {}\n\n'; // 生成order if (this.defaultData.order.length > 0) { code += `card.order = { "${this.defaultData.order.join(',')}" }\n\n`; } // 生成info code += 'card.info = {\n'; if (this.defaultData.ego) { code += ` ego = "${this.defaultData.ego}",\n`; } code += '}\n\n'; // 生成各个卡牌 Object.keys(this.cards).forEach(name => { const card = this.cards[name]; code += this.generateCardCode(name, card); }); code += 'return card'; return code; } // 生成单个卡牌代码 generateCardCode(name, card) { let code = `card["${name}"] = {\n`; code += ' base = {\n'; // 基础属性 if (card.displayname) { code += ` displayname = "${card.displayname}",\n`; } if (card.art) { code += ` art = "${card.art}",\n`; } if (card.group) { code += ` group = "${card.group}",\n`; } if (card.rarity) { code += ` rarity = "${card.rarity}",\n`; } if (card.ap) { code += ` ap = ${isNaN(card.ap) ? `"${card.ap}"` : card.ap},\n`; } if (card.type) { code += ` type = "${card.type}",\n`; } if (card.dict) { code += ` dict = "${card.dict}",\n`; } if (card.desc_global) { const desc = card.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"'); code += ` desc_global = "${desc}",\n`; } if (card.sub) { code += ` sub = "${card.sub}",\n`; } if (card.isinspiration) { code += ` isinspiration = 1,\n`; } if (card.isgod_inspiration) { code += ` isgod_inspiration = 1,\n`; } code += ' },\n'; // 变体数据 if (card.isinspiration || card.isgod_inspiration) { code += ' var = {\n'; // 灵光一闪 if (card.isinspiration && card.inspirations && card.inspirations.length > 0) { code += ' inspiration = {\n'; card.inspirations.forEach(insp => { code += ' {\n'; if (insp.ap !== undefined) { code += ` ap = ${isNaN(insp.ap) ? `"${insp.ap}"` : insp.ap},\n`; } if (insp.type) { code += ` type = "${insp.type}",\n`; } if (insp.desc_global) { const desc = insp.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"'); code += ` desc_global = "${desc}",\n`; } code += ' },\n'; }); code += ' },\n'; } // 神光一闪 if (card.isgod_inspiration && card.god_inspirations) { code += ' god_inspiration = {\n'; const gods = ['circen', 'diallos', 'nihilum', 'secred', 'vitor']; gods.forEach(god => { if (card.god_inspirations[god] && card.god_inspirations[god].length > 0) { code += ` ${god} = {\n`; card.god_inspirations[god].forEach(insp => { code += ' {\n'; if (insp.ap !== undefined) { code += ` ap = ${isNaN(insp.ap) ? `"${insp.ap}"` : insp.ap},\n`; } if (insp.type) { code += ` type = "${insp.type}",\n`; } if (insp.desc_global) { const desc = insp.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"'); code += ` desc_global = "${desc}",\n`; } code += ' },\n'; }); code += ' },\n'; } }); code += ' },\n'; } code += ' },\n'; } code += '}\n\n'; return code; } // 保存卡牌 saveCard() { if (!this.cardData.name) { alert('请输入卡牌名称!'); return; } // 克隆当前卡牌数据 const cardToSave = JSON.parse(JSON.stringify(this.cardData)); // 保存到cards对象 this.cards[cardToSave.name] = cardToSave; this.currentCard = cardToSave.name; // 更新order if (!this.defaultData.order.includes(cardToSave.name)) { this.defaultData.order.push(cardToSave.name); } // 更新列表和预览 const listContainer = document.getElementById('card-list'); if (listContainer) { this.updateCardList(listContainer); } this.updatePreview(); alert('卡牌保存成功!'); } // 新建卡牌 newCard() { this.currentCard = null; this.cardData = { name: '', displayname: '', art: '', group: '', rarity: '', god: '', ap: '', type: '攻击', dict: '', desc_global: '', sub: '', isinspiration: false, isgod_inspiration: false, inspirations: [], god_inspirations: { circen: [], diallos: [], nihilum: [], secred: [], vitor: [] } }; // 重新渲染输入区 const leftPanel = document.querySelector('.card-input-panel'); if (leftPanel) { leftPanel.innerHTML = ''; leftPanel.appendChild(this.renderFighterSelect()); leftPanel.appendChild(this.renderDefaultInfo()); leftPanel.appendChild(this.renderCardInput()); } // 清除列表选中状态 const listContainer = document.getElementById('card-list'); if (listContainer) { listContainer.querySelectorAll('.card-list-item').forEach(i => i.classList.remove('active')); } } // 加载卡牌 loadCard(name) { if (!this.cards[name]) return; this.currentCard = name; this.cardData = JSON.parse(JSON.stringify(this.cards[name])); // 重新渲染输入区 const leftPanel = document.querySelector('.card-input-panel'); if (leftPanel) { leftPanel.innerHTML = ''; leftPanel.appendChild(this.renderFighterSelect()); leftPanel.appendChild(this.renderDefaultInfo()); leftPanel.appendChild(this.renderCardInput()); } } // 加载战斗员数据 async loadFighterData() { if (!this.currentFighter) return; try { const api = new mw.Api(); const moduleName = `模块:卡牌/${this.currentFighter}`; const response = await api.get({ action: 'query', prop: 'revisions', titles: moduleName, rvprop: 'content', rvslots: 'main' }); const pages = response.query.pages; const page = Object.values(pages)[0]; if (page.revisions) { const content = page.revisions[0].slots.main['*']; this.parseLuaCode(content); // 重新渲染 this.render(); } } catch (error) { console.error('加载战斗员数据失败:', error); } } // 解析Lua代码(简化版) parseLuaCode(code) { // 这里应该实现完整的Lua代码解析 // 由于复杂度较高,这里只做基本的解析示例 // 解析order const orderMatch = code.match(/card\.order\s*=\s*{\s*"([^"]*)"\s*}/); if (orderMatch) { this.defaultData.order = orderMatch[1].split(',').map(s => s.trim()); } // 解析ego const egoMatch = code.match(/ego\s*=\s*"([^"]*)"/); if (egoMatch) { this.defaultData.ego = egoMatch[1]; } // 这里应该继续解析各个卡牌的数据 // 由于Lua语法复杂,建议使用专门的Lua解析器 } // 保存到Mediawiki async saveToMediawiki() { if (!this.currentFighter) { alert('请先选择战斗员!'); return; } const code = this.generateLuaCode(); const moduleName = `模块:卡牌/${this.currentFighter}`; try { const api = new mw.Api(); await api.postWithToken('csrf', { action: 'edit', title: moduleName, text: code, summary: '通过卡牌管理器更新', contentmodel: 'Scribunto' }); alert('保存成功!'); } catch (error) { console.error('保存失败:', error); alert('保存失败:' + error); } } // 复制代码 copyCode() { const code = this.generateLuaCode(); // 创建临时文本域 const textarea = document.createElement('textarea'); textarea.value = code; textarea.style.position = 'fixed'; textarea.style.opacity = '0'; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); alert('代码已复制到剪贴板!'); } // 绑定事件 bindEvents() { // 可以在这里添加全局事件监听 } } // 等待页面加载完成 if (mw.config.get('wgPageName') === 'Special:Card' || window.location.search.includes('cardmanager=1')) { mw.loader.using(['mediawiki.api']).then(() => { const manager = new CardManager(); manager.init(); }); } // 添加导航链接(可选) mw.loader.using(['mediawiki.util']).then(() => { mw.util.addPortletLink( 'p-tb', '?cardmanager=1', '卡牌管理器', 't-cardmanager', '打开卡牌管理器' ); }); })();
该页面使用的模板:
模板:图标
(
查看源代码
)
模板:描边
(
查看源代码
)
模板:描边/颜色
(
查看源代码
)
模板:文本
(
查看源代码
)
模板:词典
(
查看源代码
)
模块:文本
(
查看源代码
)
模块:词典
(
查看源代码
)
模块:词典/data
(
查看源代码
)
返回
MediaWiki:Card.js
。