打开/关闭搜索
搜索
打开/关闭菜单
933
1525
112
1.4万
植物大战僵尸杂交版Wiki
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
上传文件
打开/关闭外观设置菜单
notifications
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
user-interface-preferences
个人工具
创建账号
登录
查看“︁微件:ZombieEditor”︁的源代码
来自植物大战僵尸杂交版Wiki
查看
阅读
查看源代码
查看历史
associated-pages
微件
讨论
更多操作
←
微件:ZombieEditor
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您没有权限编辑
微件
命名空间内的页面。
您可以查看和复制此页面的源代码。
<includeonly> <div class="zombie-editor-widget"> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, maximum-scale=1.5"> <link rel="icon" type="image/x-icon" href="favicon.jpg"> <title>僵尸 · Wiki编辑器</title> <style> * { box-sizing: border-box; font-family: system-ui, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', sans-serif; } body { background: #2b1e2b; background-image: radial-gradient(circle at 20% 30%, #4a2e4a, #2a152a); min-height: 100vh; margin: 0; padding: 24px 16px; display: flex; justify-content: center; align-items: center; } .app-container { max-width: 1300px; width: 100%; background: rgba(30, 20, 30, 0.7); backdrop-filter: blur(8px); border: 2px solid #8b6b9e; box-shadow: 0 20px 40px rgba(0,0,0,0.6), inset 0 0 0 1px #c9a0d4; border-radius: 40px; padding: 28px 24px 32px; } h1 { margin: 0 0 8px 0; font-weight: 700; font-size: 2.5rem; letter-spacing: 2px; color: #d4b0e8; text-shadow: 3px 3px 0 #2a1530; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } h1 small { font-size: 1rem; background: #4a2e5a; padding: 6px 14px; border-radius: 40px; color: #e8d4f0; border: 1px solid #b080cc; box-shadow: inset 0 1px 3px #1a0e1a; } .subtitle { color: #c8b0d6; margin: 4px 0 24px 8px; font-style: italic; border-left: 5px solid #c08be0; padding-left: 18px; font-size: 1.1rem; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; } .import-btn { background: #5a3a70; border: 2px solid #b890d0; color: #f0d8ff; padding: 8px 20px; border-radius: 40px; font-weight: bold; cursor: pointer; box-shadow: 0 4px 0 #2a1a3a; font-size: 0.95rem; transition: all 0.1s ease; } .import-btn:active { transform: translateY(2px); box-shadow: 0 2px 0 #2a1a3a; } .editor-layout { display: flex; flex-wrap: wrap; gap: 24px; } .form-panel { flex: 2; min-width: 380px; background: #2e1f35cc; backdrop-filter: blur(4px); border: 2px solid #9e70b8; border-radius: 32px; padding: 24px 22px; box-shadow: inset 0 0 0 1px #b890cc, 0 8px 0 #1a1020; max-height: 850px; overflow-y: auto; } .form-panel::-webkit-scrollbar { width: 8px; } .form-panel::-webkit-scrollbar-track { background: #1e1428; border-radius: 20px; } .form-panel::-webkit-scrollbar-thumb { background: #9e70b8; border-radius: 20px; } .infocard-sim { background: #25182add; border-radius: 24px; padding: 16px 20px; margin-bottom: 28px; border-left: 12px solid #c080e0; box-shadow: inset 0 0 0 1px #a070b8; } .infocard-header { display: flex; align-items: center; justify-content: space-between; color: #e0c0f0; font-weight: bold; margin-bottom: 16px; font-size: 1.3rem; } .infocard-header span { background: #7a2e5a; padding: 4px 14px; border-radius: 40px; font-size: 0.9rem; border: 1px solid #d080b0; } .image-input-row { display: flex; align-items: center; gap: 8px; background: #2a1a30aa; padding: 10px 14px; border-radius: 40px; border: 1px solid #b090d0; margin-bottom: 16px; flex-wrap: wrap; } .image-input-row label { color: #e0b8f0; font-weight: 600; font-size: 0.85rem; white-space: nowrap; margin: 0; } .image-input-row input { background: #1a0e20; border: 1px solid #8b60a0; border-radius: 20px; padding: 6px 12px; color: #f0d8ff; font-size: 0.85rem; flex: 1; min-width: 80px; } .image-input-row .size-input { flex: 0.4; min-width: 60px; } .attr-editor { margin-bottom: 20px; } .attr-item { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; background: #2a1a30aa; padding: 8px 12px; border-radius: 40px; border: 1px solid #a070b8; flex-wrap: wrap; } .attr-name { width: 80px; background: transparent; border: none; color: #e0b8f0; font-weight: 600; padding: 4px 0; } .attr-value { flex: 1; background: #1a0e20; border: 1px solid #8b60a0; border-radius: 20px; padding: 6px 12px; color: #f0d8ff; } .attr-color-select { width: 70px; background: #3a2840; border: 1px solid #b090c0; border-radius: 20px; padding: 5px 6px; color: #f0e0ff; font-size: 0.85rem; } .attr-bold-check { display: flex; align-items: center; gap: 4px; color: #e0c0f0; font-size: 0.85rem; white-space: nowrap; } .attr-bold-check input { width: 18px; height: 18px; accent-color: #c080e0; } .attr-remove-btn { background: #7a2e4a; border: 1px solid #cc70a0; color: #ffc8e0; border-radius: 30px; width: 30px; height: 30px; font-weight: bold; cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 0 #3a1a2a; } .add-attr-btn { background: #5a3a70; border: 1px solid #b090d0; color: #f0d8ff; padding: 8px 18px; border-radius: 40px; font-weight: bold; cursor: pointer; box-shadow: 0 4px 0 #2a1a3a; margin-top: 8px; display: inline-block; } .input-group { margin-bottom: 24px; } label { display: block; color: #e0c8f0; font-weight: 600; margin-bottom: 6px; font-size: 1rem; } input, textarea { width: 100%; background: #1e1228; border: 2px solid #8b60a0; border-radius: 24px; padding: 12px 18px; color: #f0d8ff; font-size: 1rem; outline: none; box-shadow: inset 0 3px 8px #0c0810; } input:focus, textarea:focus { border-color: #c8a0e0; box-shadow: 0 0 0 3px #a070b888; } textarea { min-height: 100px; resize: vertical; line-height: 1.5; } .row-2col { display: flex; gap: 16px; flex-wrap: wrap; } .row-2col > div { flex: 1 1 160px; } .gallery-row, .video-row { display: flex; align-items: flex-end; gap: 10px; margin-bottom: 6px; flex-wrap: wrap; } .gallery-row .gallery-fields, .video-row .video-fields { display: flex; flex: 1; gap: 8px; flex-wrap: wrap; } .btn-icon { background: #4a3060; border: 1px solid #b890d0; color: #f0d8ff; border-radius: 30px; padding: 6px 16px; font-weight: bold; cursor: pointer; box-shadow: 0 4px 0 #2a1a38; font-size: 0.9rem; transition: all 0.1s ease; } .btn-icon:active { transform: translateY(2px); box-shadow: 0 2px 0 #2a1a38; } .btn-primary { background: #a070c0; border: none; color: #1a0e28; font-weight: 800; padding: 14px 24px; border-radius: 60px; font-size: 1.2rem; box-shadow: 0 8px 0 #5a3a78; border: 1px solid #d8b0f0; cursor: pointer; width: 100%; margin-top: 20px; transition: all 0.1s ease; } .btn-primary:active { transform: translateY(4px); box-shadow: 0 4px 0 #5a3a78; } .preview-panel { flex: 3; min-width: 380px; background: #1e1428e0; backdrop-filter: blur(4px); border: 2px solid #9e70b8; border-radius: 32px; padding: 20px 18px; box-shadow: inset 0 0 0 1px #b890cc, 0 8px 0 #1a1020; display: flex; flex-direction: column; } .preview-header { display: flex; gap: 12px; align-items: center; margin-bottom: 18px; flex-wrap: wrap; } .preview-header h2 { margin: 0; color: #d8b8f0; font-size: 1.8rem; text-shadow: 2px 2px 0 #2a1a38; } .preview-actions { margin-left: auto; display: flex; gap: 10px; } .copy-btn, .paste-btn { background: #4a3070; border: 1px solid #b8a0d0; color: #f0e0ff; padding: 10px 20px; border-radius: 40px; font-weight: bold; cursor: pointer; box-shadow: 0 4px 0 #2a1a40; transition: all 0.1s ease; } .paste-btn { background: #5a4a30; border-color: #c8b870; } .copy-btn:active, .paste-btn:active { transform: translateY(2px); box-shadow: 0 2px 0 #2a1a40; } .wiki-output { background: #0e0818; border-radius: 20px; padding: 18px 20px; border: 2px solid #a880c0; box-shadow: inset 0 0 10px #020108; font-family: 'Courier New', monospace; white-space: pre-wrap; word-break: break-word; color: #d0b8e8; font-size: 0.95rem; line-height: 1.6; max-height: 500px; overflow: auto; flex: 1; } .note { margin-top: 16px; color: #c0a8d0; font-size: 0.9rem; } .top-link { text-align: center; margin: 0 0 16px 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 16px; } .top-link a { color: #ffaaaa; font-weight: bold; } .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.7); display: none; justify-content: center; align-items: center; z-index: 1000; } .modal { background: #1e1428; border: 3px solid #9e70b8; border-radius: 32px; padding: 28px; max-width: 700px; width: 90%; max-height: 80vh; box-shadow: 0 20px 40px black; } .modal h3 { color: #d8b8f0; margin: 0 0 16px 0; } .modal p { color: #c0a8d0; margin-bottom: 12px; } .modal textarea { width: 100%; min-height: 300px; background: #0e0818; border: 2px solid #a070b8; color: #f0d8ff; font-family: 'Courier New', monospace; font-size: 0.9rem; } .modal-actions { display: flex; gap: 16px; margin-top: 20px; justify-content: flex-end; } .modal-btn { padding: 12px 28px; border-radius: 40px; font-weight: bold; cursor: pointer; border: none; font-size: 1rem; } .modal-btn.primary { background: #a070c0; color: #1a0e28; box-shadow: 0 4px 0 #5a3a78; } .modal-btn.cancel { background: #4a3a5a; color: #e0d0f0; box-shadow: 0 4px 0 #2a1a3a; } .video-section { background: #2a1a35aa; border-radius: 20px; padding: 14px 18px; margin-bottom: 24px; border: 1px solid #b080c0; } .video-header { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; } .video-header span { color: #e0b8f0; font-weight: bold; } </style> </head> <body> <div class="app-container"> <div class="top-link"> <font color="#ffaaaa">点击前往植物Wiki编辑器:<a href="https://wikitext.netlify.app/" target="_blank"><font color="#ffaaaa">前往</font></a></font> <font color="#ffaaaa">点击前往关卡Wiki编辑器:<a href="https://levelwikitext.netlify.app/" target="_blank"><font color="#ffaaaa">前往</font></a></font> </div> <h1>🧟🚧 僵尸 · Wiki编辑器 <small>杂交版僵尸</small></h1> <div class="subtitle"> <span>填写数据,一键生成标准Wiki文本</span> <button class="import-btn" id="importBtn">📥 导入现有源码</button> </div> <div class="editor-layout"> <div class="form-panel" id="formPanel"> <div class="infocard-sim"> <div class="infocard-header"> <span>📋 Infocard 属性编辑器</span> <span style="background:#6a3070;">right|图片=xxx|图片尺寸=xx|属性=...</span> </div> <div class="image-input-row"> <label>🖼️ 图片=</label> <input type="text" id="infocardImage" value="路障僵尸.png" placeholder="文件名"> <label>图片尺寸=</label> <input type="text" id="infocardImageSize" value="96px" placeholder="96px" class="size-input"> </div> <div id="attrEditorContainer" class="attr-editor"></div> <button type="button" id="addAttrBtn" class="add-attr-btn">➕ 添加属性项</button> </div> <div class="input-group"> <label>🏷️ 僵尸类型/分类</label> <input type="text" id="zombieTypeInput" value="小型僵尸"> </div> <div class="input-group"> <label>🧠 僵尸主描述</label> <input type="text" id="descLine" value="他的路障头盔,使他比普通僵尸更能承受伤害。"> </div> <div class="input-group"> <label>🖼️ 皮肤 · 画廊 <i>(可选)</i></label> <div id="galleryContainer"> <div class="gallery-row"> <div class="gallery-fields"> <input type="text" class="skinFile" value="" placeholder="文件名" style="flex:2;"> <input type="text" class="skinCaption" value="" placeholder="标题" style="flex:1.5;"> <input type="text" class="skinLink" value="" placeholder="link=" style="flex:1;"> </div> <button type="button" class="btn-icon remove-gallery-btn">✕</button> </div> </div> <div style="margin-top:10px;"><button type="button" id="addGalleryBtn" class="btn-icon" style="background:#5a3a70;">➕ 添加皮肤项</button></div> </div> <!-- 视频演示区域,位置在别名之前,但最终生成在别名下方 --> <div class="video-section"> <div class="video-header"><span>🎬 视频演示</span></div> <div id="videoContainer"> <div class="video-row"> <div class="video-fields"> <input type="text" class="videoBv" value="" placeholder="BV号" style="flex:2;"> <input type="text" class="videoWidth" value="320" placeholder="宽" style="flex:1;"> <input type="text" class="videoHeight" value="180" placeholder="高" style="flex:1;"> </div> <button type="button" class="btn-icon remove-video-btn">✕</button> </div> </div> <div style="margin-top:10px;"><button type="button" id="addVideoBtn" class="btn-icon" style="background:#5a3a70;">➕ 添加视频项</button></div> <div style="color:#c0a8d0; font-size:0.8rem; margin-top:6px;">使用BiliVideo部件,填写BV号与尺寸</div> </div> <div class="row-2col"> <div class="input-group"><label>🔓 解锁方式</label><input type="text" id="unlockInput" value="通关我是僵尸1-1解锁"></div> <div class="input-group"><label>🏷️ 别名(每行一个)</label><textarea id="aliasInput" rows="2">路障</textarea></div> </div> <div class="input-group"><label>✨ 特点(每行一个)</label><textarea id="featuresListInput" rows="3">他的路障头盔,使他比普通僵尸更能承受伤害。</textarea></div> <div class="input-group"><label>📜 宝开语</label><textarea id="poptalkInput" rows="5">和其他僵尸一样,路障僵尸盲目地向前。 但某些事物却使他停下脚步,捡起一个交通路障, 并固定在自己的脑袋上——是的,他很喜欢参加聚会。</textarea></div> <button class="btn-primary" id="generateBtn">🧟 立即生成 Wiki 文本</button> </div> <div class="preview-panel"> <div class="preview-header"> <h2>📄 Wiki输出</h2> <div class="preview-actions"> <button class="paste-btn" id="pasteToImportBtn">📋 从预览导入</button> <button class="copy-btn" id="copyBtn">📋 复制代码</button> </div> </div> <div class="wiki-output" id="wikiOutput"></div> <div class="note">⚡ 实时生成。视频演示将出现在别名下方。</div> </div> </div> </div> <div class="modal-overlay" id="importModal"> <div class="modal"> <h3>📥 导入 Wiki 源码</h3> <p>粘贴现有的僵尸 Wiki 文本</p> <textarea id="importTextarea" placeholder="在此粘贴 Wiki 源码..."></textarea> <div class="modal-actions"> <button class="modal-btn cancel" id="cancelImportBtn">取消</button> <button class="modal-btn primary" id="confirmImportBtn">解析并导入</button> </div> </div> </div> <script> (function() { const COLOR_OPTIONS = [ { value: '', label: '默认' },{ value: 'red', label: '红色' },{ value: 'blue', label: '蓝色' }, { value: 'green', label: '绿色' },{ value: 'orange', label: '橙色' },{ value: 'purple', label: '紫色' }, { value: 'gold', label: '金色' },{ value: 'brown', label: '棕色' }, { value: 'darkred', label: '深红' },{ value: 'darkgreen', label: '深绿' } ]; const COLOR_MAP = Object.fromEntries(COLOR_OPTIONS.filter(o=>o.value).map(o=>[o.value,o.value])); const DEFAULT_ATTRS = [ { name: '韧性', value: '270', color: '', bold: false }, { name: '啃食伤害', value: '100/s', color: '', bold: false }, { name: '佩戴', value: '路障(一类)', color: '', bold: false }, { name: '速度', value: '慢', color: '', bold: false }, { name: '类型', value: '小型僵尸', color: '', bold: false }, { name: '上线版本', value: 'v0.1', color: '', bold: false } ]; const attrContainer = document.getElementById('attrEditorContainer'); const infocardImage = document.getElementById('infocardImage'); const infocardImageSize = document.getElementById('infocardImageSize'); const zombieTypeInp = document.getElementById('zombieTypeInput'); const descLine = document.getElementById('descLine'); const unlockInp = document.getElementById('unlockInput'); const aliasArea = document.getElementById('aliasInput'); const featuresArea = document.getElementById('featuresListInput'); const poptalkArea = document.getElementById('poptalkInput'); const galleryContainer = document.getElementById('galleryContainer'); const videoContainer = document.getElementById('videoContainer'); const wikiOutputDiv = document.getElementById('wikiOutput'); const importModal = document.getElementById('importModal'); const importTextarea = document.getElementById('importTextarea'); function createColorSelect(sel='') { const s = document.createElement('select'); s.className='attr-color-select'; COLOR_OPTIONS.forEach(o => { const op = document.createElement('option'); op.value=o.value; op.textContent=o.label; if(o.value===sel) op.selected=true; s.appendChild(op); }); return s; } function createBoldCheck(chk=false) { const d = document.createElement('div'); d.className='attr-bold-check'; d.innerHTML = `<input type="checkbox" ${chk?'checked':''}><span>加粗</span>`; return d; } function createAttrItem(d={name:'',value:'',color:'',bold:false}) { const div = document.createElement('div'); div.className='attr-item'; const ni = document.createElement('input'); ni.type='text'; ni.className='attr-name'; ni.placeholder='属性名'; ni.value=d.name||''; const vi = document.createElement('input'); vi.type='text'; vi.className='attr-value'; vi.placeholder='属性值'; vi.value=d.value||''; const cs = createColorSelect(d.color||''); const bc = createBoldCheck(d.bold||false); const cb = bc.querySelector('input'); const rb = document.createElement('button'); rb.type='button'; rb.className='attr-remove-btn'; rb.textContent='✕'; rb.addEventListener('click',()=>{ if(attrContainer.children.length>1){ div.remove(); refreshPreview(); } else alert('至少保留一个属性项'); }); div.append(ni,vi,cs,bc,rb); ni.addEventListener('input',refreshPreview); vi.addEventListener('input',refreshPreview); cs.addEventListener('change',refreshPreview); cb.addEventListener('change',refreshPreview); return div; } function setAttrItems(a){ attrContainer.innerHTML=''; a.forEach(x=>attrContainer.appendChild(createAttrItem(x))); } function collectAttrs(){ const a=[]; attrContainer.querySelectorAll('.attr-item').forEach(item=>{ const n=item.querySelector('.attr-name').value.trim(); const v=item.querySelector('.attr-value').value.trim(); if(!n&&!v) return; a.push({name:n||'?',value:v||'',color:item.querySelector('.attr-color-select').value,bold:item.querySelector('.attr-bold-check input').checked}); }); return a; } function buildInfocard() { const img = infocardImage.value.trim() || '路障僵尸.png'; const sz = infocardImageSize.value.trim() || '96px'; const attrs = collectAttrs(); const parts = attrs.map(a => { let v = a.value; if(a.bold) v = `'''${v}'''`; if(a.color) v = `<font color=${a.color}>${v}</font>`; return `${a.name}:${v}`; }); return `{{Infocard|right|图片=${img}|图片尺寸=${sz}|属性=${parts.join(',')}}}`; } function collectGalleryItems(){ const items=[]; galleryContainer.querySelectorAll('.gallery-row').forEach(row=>{ const f=row.querySelector('.skinFile'); if(!f) return; const file=f.value.trim(), cap=row.querySelector('.skinCaption')?.value.trim()||'', link=row.querySelector('.skinLink')?.value.trim()||''; if(!file&&!cap&&!link) return; let line=file; if(cap) line+=`|${cap}`; if(link) line+=`|link=${link}`; items.push(line); }); return items; } function collectVideoItems(){ const items=[]; videoContainer.querySelectorAll('.video-row').forEach(row=>{ const bvInput = row.querySelector('.videoBv'); if(!bvInput) return; const bv = bvInput.value.trim(); const width = row.querySelector('.videoWidth')?.value.trim() || '320'; const height = row.querySelector('.videoHeight')?.value.trim() || '180'; if(!bv) return; items.push({ bv, width, height }); }); return items; } function buildWikiText(){ const infocard = buildInfocard(); const desc = descLine.value.trim() || '他的路障头盔,使他比普通僵尸更能承受伤害。'; const gItems = collectGalleryItems(); let gSection = ''; if(gItems.length>0 && gItems.some(i=>i.trim()!=='')) { gSection = `\n== 皮肤 ==\n<hr/>\n<gallery>\n${gItems.join('\n')}\n</gallery>\n`; } const videoItems = collectVideoItems(); let videoBlock = ''; if (videoItems.length > 0) { videoBlock = videoItems.map(v => `{{#widget:BiliVideo|bv=${v.bv}|width=${v.width}|height=${v.height}}}`).join('\n'); } const unlock = unlockInp.value.trim() || '通关我是僵尸1-1解锁'; const alias = aliasArea.value.trim().split('\n').filter(l=>l.trim()).map(l=>`* ${l.trim()}`).join('\n'); const feat = featuresArea.value.trim().split('\n').filter(l=>l.trim()).map(l=>`* ${l.trim()}`).join('\n'); const pop = poptalkArea.value.split('\n').map(l=>{ const t=l.trim(); return t?`'''${t}'''`:''; }).join('\n'); // 构建视频演示部分(位于别名下方) let videoSection = ''; if (videoBlock) { videoSection = `\n==视频演示==\n<hr/>\n${videoBlock}\n`; } return `{{返回僵尸列表}} ${infocard} 《植物大战僵尸杂交版》中的僵尸,${desc} <div style="display: flex; justify-content: center;"> <div style="width: fit-content; min-width: 50%;">${gSection} == 解锁方式 == <hr/> '''${unlock}''' ==别名== <hr/> ${alias} ${videoSection} == 特点 == <hr/> ${feat} == 宝开语 == <hr/> ${pop} </div> </div>`; } function refreshPreview(){ const t = buildWikiText(); wikiOutputDiv.innerHTML = t.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); } function addGalleryRow(file='',caption='',link=''){ const div=document.createElement('div'); div.className='gallery-row'; div.innerHTML=`<div class="gallery-fields"><input type="text" class="skinFile" value="${file.replace(/"/g,'"')}" placeholder="文件名" style="flex:2;"><input type="text" class="skinCaption" value="${caption.replace(/"/g,'"')}" placeholder="标题" style="flex:1.5;"><input type="text" class="skinLink" value="${link.replace(/"/g,'"')}" placeholder="link=" style="flex:1;"></div><button type="button" class="btn-icon remove-gallery-btn">✕</button>`; galleryContainer.appendChild(div); div.querySelector('.remove-gallery-btn').addEventListener('click',function(){ if(galleryContainer.children.length>1){ div.remove(); refreshPreview(); } else alert('至少保留一项'); }); div.querySelectorAll('input').forEach(i=>i.addEventListener('input',refreshPreview)); refreshPreview(); } function addVideoRow(bv='', width='320', height='180'){ const div=document.createElement('div'); div.className='video-row'; div.innerHTML=`<div class="video-fields"><input type="text" class="videoBv" value="${bv.replace(/"/g,'"')}" placeholder="BV号" style="flex:2;"><input type="text" class="videoWidth" value="${width}" placeholder="宽" style="flex:1;"><input type="text" class="videoHeight" value="${height}" placeholder="高" style="flex:1;"></div><button type="button" class="btn-icon remove-video-btn">✕</button>`; videoContainer.appendChild(div); div.querySelector('.remove-video-btn').addEventListener('click',function(){ if(videoContainer.children.length>1){ div.remove(); refreshPreview(); } else alert('至少保留一项视频'); }); div.querySelectorAll('input').forEach(i=>i.addEventListener('input',refreshPreview)); refreshPreview(); } function clearGallery(){ while(galleryContainer.children.length>0) galleryContainer.removeChild(galleryContainer.firstChild); } function setGalleryItems(items){ clearGallery(); if(items.length===0) addGalleryRow('','',''); else items.forEach(i=>addGalleryRow(i.file,i.caption,i.link)); } function clearVideo(){ while(videoContainer.children.length>0) videoContainer.removeChild(videoContainer.firstChild); } function setVideoItems(items){ clearVideo(); if(items.length===0) addVideoRow('','320','180'); else items.forEach(v=>addVideoRow(v.bv, v.width, v.height)); } function parseWikiSource(src){ try { let img='路障僵尸.png', sz='96px'; const attrs=[]; const im = src.match(/{{Infocard\|right\|图片=([^|]+)\|图片尺寸=([^|]+)\|属性=([^}]+)}}/); if(im){ img=im[1].trim(); sz=im[2].trim(); const attrStr=im[3]; const parts=[]; let depth=0, cur=''; for(let i=0;i<attrStr.length;i++){ const ch=attrStr[i]; if(ch==='<') depth++; if(ch==='>') depth--; if(ch===','&&depth===0){ parts.push(cur); cur=''; } else cur+=ch; } if(cur) parts.push(cur); parts.forEach(p=>{ const ci=p.indexOf(':'); if(ci===-1) return; const name=p.substring(0,ci).trim(); let value=p.substring(ci+1).trim(); let color='', bold=false; const fm=value.match(/<font color=([^>]+)>(.*?)<\/font>/i); if(fm){ const cn=fm[1].replace(/['"]/g,''); if(COLOR_MAP[cn]) color=cn; value=fm[2]; } const bm=value.match(/^'''(.+)'''$/); if(bm){ bold=true; value=bm[1]; } attrs.push({name,value,color,bold}); }); } const descM=src.match(/《植物大战僵尸杂交版》中的僵尸,([^\n]+)/); const desc=descM?descM[1].trim():''; const gItems=[]; const gm=src.match(/<gallery>\s*([\s\S]*?)\s*<\/gallery>/); if(gm){ gm[1].trim().split('\n').forEach(l=>{ l=l.trim(); if(!l) return; const p=l.split('|'); gItems.push({file:p[0]||'',caption:p[1]||'',link:p[2]&&p[2].startsWith('link=')?p[2].substring(5):''}); }); } const videoItems=[]; const videoRegex = /{{#widget:BiliVideo\|bv=([^|]+)\|width=(\d+)\|height=(\d+)}}/g; let vm; while((vm=videoRegex.exec(src))!==null){ videoItems.push({bv:vm[1], width:vm[2], height:vm[3]}); } const unlockM=src.match(/== 解锁方式 ==\s*<hr\/>\s*'''([^']+)'''/); const unlock=unlockM?unlockM[1]:''; const aliasL=[], featL=[]; const as=src.match(/==别名==\s*<hr\/>\s*([\s\S]*?)(?=\n==|$)/); if(as) as[1].split('\n').forEach(l=>{ const m=l.match(/^\*\s*(.+)/); if(m) aliasL.push(m[1]); }); const fs=src.match(/== 特点 ==\s*<hr\/>\s*([\s\S]*?)(?=\n==|$)/); if(fs) fs[1].split('\n').forEach(l=>{ const m=l.match(/^\*\s*(.+)/); if(m) featL.push(m[1]); }); const popL=[]; const ps=src.match(/== 宝开语 ==\s*<hr\/>\s*([\s\S]*?)(?=\s*<\/div>|$)/); if(ps) ps[1].split('\n').forEach(l=>{ const m=l.match(/^'''(.+)'''$/); if(m) popL.push(m[1]); else if(l.trim()) popL.push(l.trim()); }); return {image:img,imageSize:sz,attrs:attrs.length>0?attrs:DEFAULT_ATTRS,desc,galleryItems:gItems,videoItems:videoItems,unlock,aliasLines:aliasL,featureLines:featL,poptalkLines:popL}; } catch(e){ console.error(e); return null; } } function applyParsedData(d){ if(!d) return; if(d.image) infocardImage.value=d.image; if(d.imageSize) infocardImageSize.value=d.imageSize; if(d.attrs&&d.attrs.length>0) setAttrItems(d.attrs); if(d.desc) descLine.value=d.desc; if(d.galleryItems&&d.galleryItems.length>0) setGalleryItems(d.galleryItems); if(d.videoItems&&d.videoItems.length>0) setVideoItems(d.videoItems); if(d.unlock) unlockInp.value=d.unlock; if(d.aliasLines&&d.aliasLines.length>0) aliasArea.value=d.aliasLines.join('\n'); if(d.featureLines&&d.featureLines.length>0) featuresArea.value=d.featureLines.join('\n'); if(d.poptalkLines&&d.poptalkLines.length>0) poptalkArea.value=d.poptalkLines.join('\n'); refreshPreview(); } function importFromSource(src){ const d=parseWikiSource(src); if(d){ applyParsedData(d); alert('✅ 导入成功!'); } else alert('❌ 解析失败'); } function bindEvents(){ document.getElementById('addAttrBtn').addEventListener('click',()=>{ attrContainer.appendChild(createAttrItem()); refreshPreview(); }); document.getElementById('addGalleryBtn').addEventListener('click',()=>addGalleryRow('','','')); document.getElementById('addVideoBtn').addEventListener('click',()=>addVideoRow('','320','180')); infocardImage.addEventListener('input',refreshPreview); infocardImageSize.addEventListener('input',refreshPreview); [zombieTypeInp,descLine,unlockInp,aliasArea,featuresArea,poptalkArea].forEach(i=>i.addEventListener('input',refreshPreview)); document.getElementById('generateBtn').addEventListener('click',refreshPreview); document.getElementById('copyBtn').addEventListener('click',async()=>{ try{ await navigator.clipboard.writeText(buildWikiText()); alert('✅ 已复制'); } catch{ alert('❌ 复制失败'); } }); galleryContainer.addEventListener('input',e=>{ if(e.target.classList.contains('skinFile')||e.target.classList.contains('skinCaption')||e.target.classList.contains('skinLink')) refreshPreview(); }); videoContainer.addEventListener('input',e=>{ if(e.target.classList.contains('videoBv')||e.target.classList.contains('videoWidth')||e.target.classList.contains('videoHeight')) refreshPreview(); }); document.getElementById('importBtn').addEventListener('click',()=>{ importTextarea.value=''; importModal.style.display='flex'; }); document.getElementById('cancelImportBtn').addEventListener('click',()=>importModal.style.display='none'); document.getElementById('confirmImportBtn').addEventListener('click',()=>{ const s=importTextarea.value.trim(); if(s){ importFromSource(s); importModal.style.display='none'; } else alert('请粘贴源码'); }); document.getElementById('pasteToImportBtn').addEventListener('click',()=>importFromSource(buildWikiText())); importModal.addEventListener('click',e=>{ if(e.target===importModal) importModal.style.display='none'; }); } function init(){ attrContainer.innerHTML=''; DEFAULT_ATTRS.forEach(a=>attrContainer.appendChild(createAttrItem(a))); clearGallery(); addGalleryRow('','',''); clearVideo(); addVideoRow('','320','180'); bindEvents(); refreshPreview(); } init(); })(); </script> </body> </html> </div> </includeonly>
返回
微件:ZombieEditor
。
查看“︁微件:ZombieEditor”︁的源代码
来自植物大战僵尸杂交版Wiki