MediaWiki:Common.js:修订间差异
来自Mindustry中文wiki
无编辑摘要 |
(没力气改映射表错误了,仅仅只是做了unicdoe转中文。) |
||
| 第330行: | 第330行: | ||
btn.setAttribute('aria-expanded', 'true'); | btn.setAttribute('aria-expanded', 'true'); | ||
btn.title = '展开/收起'; | btn.title = '展开/收起'; | ||
btn.textContent = ' | btn.textContent = '▾'; | ||
// Inline style fallback: in case Timeless.css is not loaded yet. | // Inline style fallback: in case Timeless.css is not loaded yet. | ||
| 第391行: | 第391行: | ||
headingBlock.classList.toggle('mdtFoldCollapsed', collapsed); | headingBlock.classList.toggle('mdtFoldCollapsed', collapsed); | ||
btn.setAttribute('aria-expanded', String(!collapsed)); | btn.setAttribute('aria-expanded', String(!collapsed)); | ||
btn.textContent = collapsed ? ' | btn.textContent = collapsed ? '▸' : '▾'; | ||
if (body) { | if (body) { | ||
body.classList.toggle('mdtFoldHidden', collapsed); | body.classList.toggle('mdtFoldHidden', collapsed); | ||
| 第585行: | 第585行: | ||
return String(text || '') | return String(text || '') | ||
.replace(/\s+/g, ' ') | .replace(/\s+/g, ' ') | ||
.replace(/[ | .replace(/[▸▾]/g, '') | ||
.trim(); | .trim(); | ||
} | } | ||
| 第861行: | 第861行: | ||
return String(text || '') | return String(text || '') | ||
.replace(/\s+/g, ' ') | .replace(/\s+/g, ' ') | ||
.replace(/[ | .replace(/[▸▾]/g, '') | ||
.trim(); | .trim(); | ||
} | } | ||
| 第1,027行: | 第1,027行: | ||
openBtn.type = 'button'; | openBtn.type = 'button'; | ||
openBtn.className = 'mdtFloatTocBtn'; | openBtn.className = 'mdtFloatTocBtn'; | ||
openBtn.setAttribute('aria-label', ' | openBtn.setAttribute('aria-label', '目录'); | ||
openBtn.textContent = ' | openBtn.textContent = '≡'; | ||
wrap.appendChild(openBtn); | wrap.appendChild(openBtn); | ||
| 第1,034行: | 第1,034行: | ||
panel.className = 'mdtFloatTocPanel'; | panel.className = 'mdtFloatTocPanel'; | ||
panel.setAttribute('role', 'dialog'); | panel.setAttribute('role', 'dialog'); | ||
panel.setAttribute('aria-label', ' | panel.setAttribute('aria-label', '目录'); | ||
wrap.appendChild(panel); | wrap.appendChild(panel); | ||
| 第1,044行: | 第1,044行: | ||
topBtn.type = 'button'; | topBtn.type = 'button'; | ||
topBtn.className = 'mdtFloatTocTop'; | topBtn.className = 'mdtFloatTocTop'; | ||
topBtn.textContent = ' | topBtn.textContent = '↑ 返回顶部'; | ||
head.appendChild(topBtn); | head.appendChild(topBtn); | ||
var title = document.createElement('div'); | var title = document.createElement('div'); | ||
title.className = 'mdtFloatTocTitle'; | title.className = 'mdtFloatTocTitle'; | ||
title.textContent = ' | title.textContent = '目录'; | ||
head.appendChild(title); | head.appendChild(title); | ||
| 第1,055行: | 第1,055行: | ||
closeBtn.type = 'button'; | closeBtn.type = 'button'; | ||
closeBtn.className = 'mdtFloatTocClose'; | closeBtn.className = 'mdtFloatTocClose'; | ||
closeBtn.setAttribute('aria-label', ' | closeBtn.setAttribute('aria-label', '关闭'); | ||
closeBtn.textContent = 'X'; | closeBtn.textContent = 'X'; | ||
head.appendChild(closeBtn); | head.appendChild(closeBtn); | ||
| 第1,099行: | 第1,099行: | ||
toggle.type = 'button'; | toggle.type = 'button'; | ||
toggle.className = 'mdtFloatTocGroupToggle'; | toggle.className = 'mdtFloatTocGroupToggle'; | ||
toggle.setAttribute('aria-label', ' | toggle.setAttribute('aria-label', '展开/收起'); | ||
toggle.setAttribute('aria-expanded', 'false'); | toggle.setAttribute('aria-expanded', 'false'); | ||
toggle.textContent = '>'; | toggle.textContent = '>'; | ||
| 第1,288行: | 第1,288行: | ||
var MDT_ICON_MAP = { | var MDT_ICON_MAP = { | ||
' | '铜': 'Item-copper-ui.png', | ||
' | '钰': 'Item-lead-ui.png', | ||
' | '煤炭': 'Item-coal-ui.png', | ||
' | '石墨': 'Item-graphite-ui.png', | ||
' | '钛': 'Item-titanium-ui.png', | ||
' | '钱': 'Item-thorium-ui.png', | ||
' | '硅': 'Item-silicon-ui.png', | ||
' | '塑钢': 'Item-plastanium-ui.png', | ||
' | '相织布': 'Item-phase-fabric-ui.png', | ||
' | '巨浪合金': 'Item-surge-alloy-ui.png', | ||
' | '孢子荐': 'Item-spore-pod-ui.png', | ||
' | '沙': 'Item-sand-ui.png', | ||
' | '爆炸混合物': 'Item-blast-compound-ui.png', | ||
' | '硫化物': 'ohno.png', | ||
' | '钢化玻璃': 'Item-metaglass-ui.png', | ||
' | '废料': 'Item-scrap-ui.png', | ||
' | '裂变产物': 'Item-fissile-matter-ui.png', | ||
' | '钽': 'Item-beryllium-ui.png', | ||
' | '钞': 'Item-tungsten-ui.png', | ||
' | '氧化物': 'Item-oxide-ui.png', | ||
' | '碳化物': 'Item-carbide-ui.png', | ||
' | '休眠囊肿': 'Item-dormant-cyst-ui.png', | ||
' | '水': 'Liquid-water-ui.png', | ||
' | '矿渣': 'Liquid-slag-ui.png', | ||
' | '石油': 'Liquid-oil-ui.png', | ||
' | '冷冻液': 'Liquid-cryofluid-ui.png', | ||
' | '瘤液': 'Liquid-neoplasm-ui.png', | ||
' | '芳油': 'Liquid-arkycite-ui.png', | ||
' | '鋠液': 'Liquid-gallium-ui.png', | ||
' | '氧氧': 'Liquid-ozone-ui.png', | ||
' | '氢气': 'Liquid-hydrogen-ui.png', | ||
' | '氮气': 'Liquid-nitrogen-ui.png', | ||
' | '氮气': 'Liquid-cyanogen-ui.png', | ||
' | '尖刀': 'Unit-dagger-ui.png', | ||
' | '战锤': 'Unit-mace-ui.png', | ||
' | '堡垒': 'Unit-fortress-ui.png', | ||
' | '新星': 'Unit-nova-ui.png', | ||
' | '恒星': 'Unit-pulsar-ui.png', | ||
' | '耀星': 'Unit-quasar-ui.png', | ||
' | '爬虫': 'Unit-crawler-ui.png', | ||
' | '毒螞': 'Unit-atrax-ui.png', | ||
' | '血螲': 'Unit-spiroct-ui.png', | ||
' | '毒蛇': 'Unit-arkyid-ui.png', | ||
' | '天蝎': 'Unit-toxopid-ui.png', | ||
' | '星辉': 'Unit-stell-ui.png', | ||
' | '天垰': 'Unit-vela-ui.png', | ||
' | '苍穹': 'Unit-corvus-ui.png', | ||
' | '月影': 'Unit-antumbra-ui.png', | ||
' | '日蚁': 'Unit-eclipse-ui.png', | ||
' | '独影': 'Unit-obviate-ui.png', | ||
' | '幻型': 'Unit-elude-ui.png', | ||
' | '巨像': 'Unit-emanate-ui.png', | ||
' | '雷雷': 'Unit-evoke-ui.png', | ||
' | '要塞': 'Unit-conquer-ui.png', | ||
' | '棒鱼': 'Unit-bryde-ui.png', | ||
' | '飞鲨': 'Unit-minke-ui.png', | ||
' | '战鲸': 'Unit-sei-ui.png', | ||
' | '蛹龙': 'Unit-omura-ui.png', | ||
' | '海神': 'Unit-retusa-ui.png', | ||
' | '潜螺': 'Unit-cyerce-ui.png', | ||
' | '电鳊': 'Unit-oxynoe-ui.png', | ||
' | '江豚': 'Unit-risso-ui.png', | ||
' | '玄武': 'Unit-navanax-ui.png', | ||
' | '龙王': 'Unit-anthicus-ui.png', | ||
' | '阿尔法': 'Unit-alpha-ui.png', | ||
' | '贝塔': 'Unit-beta-ui.png', | ||
' | '伽马': 'Unit-gamma-ui.png', | ||
' | '权杖': 'Unit-scepter-ui.png', | ||
' | '王座': 'Unit-reign-ui.png', | ||
' | '灾星': 'Unit-scathe-ui.png', | ||
' | '死星': 'Unit-horizon-ui.png', | ||
' | '围护': 'Unit-avert-ui.png', | ||
' | '徙迹': 'Unit-locus-ui.png', | ||
' | '准绳': 'Unit-precept-ui.png', | ||
' | '征服': 'Unit-vanquish-ui.png', | ||
' | '领主': 'Unit-tecta-ui.png', | ||
' | '天守': 'Unit-collaris-ui.png', | ||
' | '天赐': 'Unit-disrupt-ui.png', | ||
' | '天灾': 'Unit-quell-ui.png', | ||
' | '天理': 'Unit-elude-ui.png', | ||
' | '天帝': 'Unit-emanate-ui.png', | ||
' | '拉脱': 'Unit-flare-ui.png', | ||
' | '遮蔽': 'Unit-horizon-ui.png', | ||
' | '消散': 'Unit-disperse-ui.png', | ||
' | '遼止': 'Unit-obviate-ui.png', | ||
' | '悲恱': 'Unit-merui-ui.png', | ||
' | '苏醒': 'Unit-emanate-ui.png', | ||
' | '策动': 'Unit-incite-ui.png', | ||
' | '发散': 'Unit-disperse-ui.png', | ||
' | '货运无人机': 'Unit-cargo-drone-ui.png', | ||
' | '装配无人机': 'Unit-assembly-drone-ui.png', | ||
'Latum': 'Unit-latum-ui.png', | 'Latum': 'Unit-latum-ui.png', | ||
'Renale': 'Unit-renale-ui.png', | 'Renale': 'Unit-renale-ui.png', | ||
' | '差扰': 'ohno.png', | ||
' | '悬崖': 'Block-cliff-ui.png', | ||
' | '砂岩': 'Block-dacite-ui.png', | ||
' | '玄武岩石块': 'Block-basalt-boulder-ui.png', | ||
' | '窑炉': 'Block-kiln-ui.png', | ||
' | '石墨压缩机': 'Block-graphite-press-ui.png', | ||
' | '多重压缩机': 'Block-multi-press-ui.png', | ||
' | '敌人出生点': 'Block-spawn-ui.png', | ||
' | '移除墙体': 'Block-remove-wall-ui.png', | ||
' | '移除矿': 'Block-remove-ore-ui.png', | ||
' | '初代核心': 'Block-core-shard-ui.png', | ||
' | '次代核心': 'Block-core-foundation-ui.png', | ||
' | '终代核心': 'Block-core-nucleus-ui.png', | ||
' | '双管': 'Block-duo-ui.png', | ||
' | '火焰': 'Block-scorch-ui.png', | ||
' | '分裂': 'Block-ripple-ui.png', | ||
' | '冰霍': 'Block-hail-ui.png', | ||
' | '蓝瑞': 'Block-lancer-ui.png', | ||
' | '传送带': 'Block-conveyor-ui.png', | ||
' | '钛传送带': 'Block-titanium-conveyor-ui.png', | ||
' | '塑钢传送带': 'Block-plastanium-conveyor-ui.png', | ||
' | '装甲传送带': 'Block-armored-conveyor-ui.png', | ||
' | '交叉器': 'Block-junction-ui.png', | ||
' | '路由器': 'Block-router-ui.png', | ||
' | '分配器': 'Block-distributor-ui.png', | ||
' | '分类器': 'Block-sorter-ui.png', | ||
' | '反向分类器': 'Block-inverted-sorter-ui.png', | ||
' | '信息板': 'Block-message-ui.png', | ||
' | '强化信息板': 'Block-reinforced-message-ui.png', | ||
' | '世界信息板': 'Block-world-message-ui.png', | ||
' | '世界开关': 'Block-world-switch-ui.png', | ||
' | '照明器': 'Block-illuminator-ui.png', | ||
' | '溢流门': 'Block-overflow-gate-ui.png', | ||
' | '反向溢流门': 'Block-underflow-gate-ui.png', | ||
' | '硅冶炼厂': 'Block-silicon-smelter-ui.png', | ||
' | '相织布编织器': 'Block-phase-weaver-ui.png', | ||
' | '粉碎机': 'Block-pulverizer-ui.png', | ||
' | '冷冻液混合器': 'Block-cryofluid-mixer-ui.png', | ||
' | '熔炉': 'Block-melter-ui.png', | ||
' | '焚化炉': 'Block-incinerator-ui.png', | ||
' | '孢子压缩机': 'Block-spore-press-ui.png', | ||
' | '分离机': 'Block-separator-ui.png', | ||
' | '煤炭离心机': 'Block-coal-centrifuge-ui.png', | ||
' | '电力节点': 'Block-power-node-ui.png', | ||
' | '大型电力节点': 'Block-power-node-large-ui.png', | ||
' | '巨浪电力塔': 'Block-surge-tower-ui.png', | ||
' | '二极管': 'Block-diode-ui.png', | ||
' | '电池': 'Block-battery-ui.png', | ||
' | '大型电池': 'Block-battery-large-ui.png', | ||
' | '火力发电机': 'Block-combustion-generator-ui.png', | ||
' | '涡轮发电机': 'Block-steam-generator-ui.png', | ||
' | '温差发电机': 'Block-thermal-generator-ui.png', | ||
' | '冲击反应堆': 'Block-impact-reactor-ui.png', | ||
' | '机械钻头': 'Block-mechanical-drill-ui.png', | ||
' | '气动钻头': 'Block-pneumatic-drill-ui.png', | ||
' | '激光钻头': 'Block-laser-drill-ui.png', | ||
' | '抽水机': 'Block-water-extractor-ui.png', | ||
' | '培养机': 'Block-cultivator-ui.png', | ||
' | '导管': 'Block-conduit-ui.png', | ||
' | '机械泵': 'Block-mechanical-pump-ui.png', | ||
' | '物品源': 'Block-item-source-ui.png', | ||
' | '物品黑洞': 'Block-item-void-ui.png', | ||
' | '液体源': 'Block-liquid-source-ui.png', | ||
' | '液体黑洞': 'Block-liquid-void-ui.png', | ||
' | '电力黑洞': 'Block-power-void-ui.png', | ||
' | '电力源': 'Block-power-source-ui.png', | ||
' | '装卸器': 'Block-unloader-ui.png', | ||
' | '仓库': 'Block-vault-ui.png', | ||
' | '波浪': 'Block-wave-ui.png', | ||
' | '海嗔': 'Block-tsunami-ui.png', | ||
' | '蜂群': 'Block-swarmer-ui.png', | ||
' | '齐射': 'Block-salvo-ui.png', | ||
' | '浪涌': 'Block-surge-ui.png', | ||
' | '相织布传送带桥': 'Block-phase-conveyor-ui.png', | ||
' | '传送带桥': 'Block-bridge-conveyor-ui.png', | ||
' | '塑钢压缩机': 'Block-plastanium-compressor-ui.png', | ||
' | '硫化物混合器': 'Block-sulfide-mixer-ui.png', | ||
' | '爆炸物混合器': 'Block-blast-mixer-ui.png', | ||
' | '太阳能板': 'Block-solar-panel-ui.png', | ||
' | '大型太阳能板': 'Block-solar-panel-large-ui.png', | ||
' | '石油钻井': 'Block-oil-extractor-ui.png', | ||
' | '维修点': 'Block-repair-point-ui.png', | ||
' | '维修塔': 'Block-repair-turret-ui.png', | ||
' | '脉冲导管': 'Block-pulse-conduit-ui.png', | ||
' | '电镀导管': 'Block-plated-conduit-ui.png', | ||
' | '相织布导管桥': 'Block-phase-conduit-ui.png', | ||
' | '流体路由器': 'Block-liquid-router-ui.png', | ||
' | '流体储罐': 'Block-liquid-tank-ui.png', | ||
' | '流体容器': 'Block-liquid-container-ui.png', | ||
' | '流体交叉器': 'Block-liquid-junction-ui.png', | ||
' | '导管桥': 'Block-bridge-conduit-ui.png', | ||
' | '回转泵': 'Block-rotary-pump-ui.png', | ||
' | '钱反应堆': 'Block-thorium-reactor-ui.png', | ||
' | '质量驱动器': 'Block-mass-driver-ui.png', | ||
' | '爆破钻头': 'Block-blast-drill-ui.png', | ||
' | '脉冲泵': 'Block-impulse-pump-ui.png', | ||
' | '热能发电机': 'Block-differential-generator-ui.png', | ||
' | '合金冶炼厂': 'Block-alloy-smelter-ui.png', | ||
' | '修理器': 'Block-mender-ui.png', | ||
' | '修理投影': 'Block-mend-projector-ui.png', | ||
' | '合金墙': 'Block-surge-wall-ui.png', | ||
' | '大型合金墙': 'Block-surge-wall-large-ui.png', | ||
' | '气旋': 'Block-cyclone-ui.png', | ||
' | '雷光': 'Block-arc-ui.png', | ||
' | '脉冲地雷': 'Block-shock-mine-ui.png', | ||
' | '超速投影': 'Block-overdrive-projector-ui.png', | ||
' | '力墙投影': 'Block-force-projector-ui.png', | ||
' | '电弧': 'Block-arc-ui.png', | ||
' | 'RTG发电机': 'Block-rtg-generator-ui.png', | ||
' | '幻影': 'Block-phantom-ui.png', | ||
' | '熔毁': 'Block-meltdown-ui.png', | ||
' | '厄兆': 'Block-afflict-ui.png', | ||
' | '容器': 'Block-container-ui.png', | ||
' | '发射台': 'Block-launch-pad-ui.png', | ||
' | '接收台': 'Block-landing-pad-ui.png', | ||
' | '裂解': 'Block-disassembler-ui.png', | ||
' | '陆军工厂': 'Block-ground-factory-ui.png', | ||
' | '空军工厂': 'Block-air-factory-ui.png', | ||
' | '海军工厂': 'Block-naval-factory-ui.png', | ||
' | '数增级单位重构工厂': 'Block-additive-reconstructor-ui.png', | ||
' | '倍乘级单位重构工厂': 'Block-multiplicative-reconstructor-ui.png', | ||
' | '多幂级单位重构工厂': 'Block-exponential-reconstructor-ui.png', | ||
' | '无量级单位重构工厂': 'Block-tetrative-reconstructor-ui.png', | ||
' | '载荷传送带': 'Block-payload-conveyor-ui.png', | ||
' | '载荷路由器': 'Block-payload-router-ui.png', | ||
' | '物品管道': 'Block-duct-ui.png', | ||
' | '物品管道路由器': 'Block-duct-router-ui.png', | ||
' | '物品管道桥': 'Block-duct-bridge-ui.png', | ||
' | '大型载荹质量驱动器': 'Block-large-payload-mass-driver-ui.png', | ||
' | '载荹黑洞': 'Block-payload-void-ui.png', | ||
' | '载荹源': 'Block-payload-source-ui.png', | ||
' | '解离机': 'Block-disassembler-ui.png', | ||
' | '热能坙坙': 'Block-slag-heater-ui.png', | ||
' | '超速窄顶': 'Block-overdrive-dome-ui.png', | ||
' | '行星际加速器': 'Block-interplanetary-accelerator-ui.png', | ||
' | '勋筑器': 'Block-constructor-ui.png', | ||
' | '大型勋筑器': 'Block-large-constructor-ui.png', | ||
' | '大型解构器': 'Block-deconstructor-ui.png', | ||
' | '载荹装载器': 'Block-payload-loader-ui.png', | ||
' | '载荹卸载器': 'Block-payload-unloader-ui.png', | ||
' | '热量源': 'Block-heat-source-ui.png', | ||
' | '空': 'Block-empty-ui.png', | ||
' | '流纹岩坑': 'Block-rhyolite-crater-ui.png', | ||
' | '粗糙流纹岩': 'Block-rough-rhyolite-ui.png', | ||
' | '流纹岩': 'Block-rhyolite-ui.png', | ||
' | '黄石': 'Block-yellow-stone-ui.png', | ||
' | '碳石': 'Block-carbon-stone-ui.png', | ||
' | '铁石': 'Block-ferric-stone-ui.png', | ||
' | '铁际石坑': 'Block-ferric-craters-ui.png', | ||
' | '钽石': 'Block-beryllic-stone-ui.png', | ||
' | '晶石': 'Block-crystalline-stone-ui.png', | ||
' | '晶石地板': 'Block-crystal-floor-ui.png', | ||
' | '黄石地板': 'Block-yellow-stone-plates-ui.png', | ||
' | '红石': 'Block-red-stone-ui.png', | ||
' | '高密红石': 'Block-dense-red-stone-ui.png', | ||
' | '红冰': 'Block-red-ice-ui.png', | ||
//' | //'芳油': 'Block-arkyic-stone-ui.png', 这是地板!ai都不看重复的吗 | ||
' | '芳石': 'Block-arkyic-stone-ui.png', | ||
' | '流纹石喷口': 'Block-rhyolite-vent-ui.png', | ||
' | '碳石喷口': 'Block-carbon-vent-ui.png', | ||
' | '芳石喷口': 'Block-arkyic-vent-ui.png', | ||
' | '黄石喷口': 'Block-yellow-stone-vent-ui.png', | ||
' | '红石喷口': 'Block-red-stone-vent-ui.png', | ||
' | '晶石喷口': 'Block-crystalline-vent-ui.png', | ||
' | '岩石喷口': 'Block-stone-vent-ui.png', | ||
' | '玄武岩喷口': 'Block-basalt-vent-ui.png', | ||
' | '红地垫': 'Block-redmat-ui.png', | ||
' | '蓝地垫': 'Block-bluemat-ui.png', | ||
' | '核心区': 'Block-core-zone-ui.png', | ||
' | '风化墙': 'Block-regolith-wall-ui.png', | ||
' | '黄石墙': 'Block-yellow-stone-wall-ui.png', | ||
' | '流纹岩墙': 'Block-rhyolite-wall-ui.png', | ||
' | '碳石墙': 'Block-carbon-wall-ui.png', | ||
' | '铁石墙': 'Block-ferric-stone-wall-ui.png', | ||
' | '钽石墙': 'Block-beryllic-stone-wall-ui.png', | ||
' | '芳石墙': 'Block-arkyic-wall-ui.png', | ||
' | '晶石墙': 'Block-crystalline-stone-wall-ui.png', | ||
' | '红冰墙': 'Block-red-ice-wall-ui.png', | ||
' | '红石墙': 'Block-red-stone-wall-ui.png', | ||
' | '红钻墙': 'Block-red-diamond-wall-ui.png', | ||
' | '赤藻': 'Block-redweed-ui.png', | ||
' | '紫灌木丛': 'Block-pur-bush-ui.png', | ||
' | '黄珊瑚': 'Block-yellowcoral-ui.png', | ||
' | '碳石块': 'Block-carbon-boulder-ui.png', | ||
' | '铁石块': 'Block-ferric-boulder-ui.png', | ||
' | '钽石块': 'Block-beryllic-boulder-ui.png', | ||
' | '黄石块': 'Block-yellow-stone-boulder-ui.png', | ||
' | '芳石块': 'Block-arkyic-boulder-ui.png', | ||
' | '水晶簇': 'Block-crystal-cluster-ui.png', | ||
' | '鲜艳水晶簇': 'Block-vibrant-crystal-cluster-ui.png', | ||
' | '风化晶体': 'Block-weathered-crystal-ui.png', | ||
' | '晶石球': 'Block-crystal-orbs-ui.png', | ||
' | '晶石块': 'Block-crystal-blocks-ui.png', | ||
' | '红冰石块': 'Block-red-ice-boulder-ui.png', | ||
' | '流纹石块': 'Block-rhyolite-boulder-ui.png', | ||
' | '红石块': 'Block-red-stone-boulder-ui.png', | ||
' | '石墨墙': 'Block-graphitic-wall-ui.png', | ||
' | '电弧硅炉': 'Block-silicon-arc-furnace-ui.png', | ||
' | '电解机': 'Block-electrolyzer-ui.png', | ||
' | '大气收集器': 'Block-atmospheric-concentrator-ui.png', | ||
' | '氧化室': 'Block-oxidation-chamber-ui.png', | ||
' | '电制热机': 'Block-electric-heater-ui.png', | ||
' | '矿渣制热机': 'Block-slag-heater-ui.png', | ||
' | '相织制热机': 'Block-phase-heater-ui.png', | ||
' | '热量传输机': 'Block-heat-redirector-ui.png', | ||
' | '小型热量传输机': 'Block-small-heat-redirector-ui.png', | ||
' | '热量路由器': 'Block-heat-router-ui.png', | ||
' | '矿渣焚化炉': 'Block-slag-incinerator-ui.png', | ||
' | '碳化物坙坙': 'Block-carbide-crucible-ui.png', | ||
' | '矿渣离心机': 'Block-slag-centrifuge-ui.png', | ||
' | '合金坙坙': 'Block-alloy-crucible-ui.png', | ||
' | '氧合成机': 'Block-cyanogen-synthesizer-ui.png', | ||
' | '相织布合成机': 'Block-phase-synthesizer-ui.png', | ||
' | '热量反应堆': 'Block-heat-reactor-ui.png', | ||
' | '钽墙': 'Block-beryllium-wall-ui.png', | ||
' | '大型钽墙': 'Block-beryllium-wall-large-ui.png', | ||
' | '钞墙': 'Block-tungsten-wall-ui.png', | ||
' | '大型钞墙': 'Block-tungsten-wall-large-ui.png', | ||
' | '防爆闸门': 'Block-blast-door-ui.png', | ||
' | '碳化物墙': 'Block-carbide-wall-ui.png', | ||
' | '大型碳化物墙': 'Block-carbide-wall-large-ui.png', | ||
' | '强化合金墙': 'Block-reinforced-surge-wall-ui.png', | ||
' | '大型强化合金墙': 'Block-reinforced-surge-wall-large-ui.png', | ||
' | '盾墙': 'Block-shielded-wall-ui.png', | ||
' | '雷达': 'Block-radar-ui.png', | ||
' | '建造塔': 'Block-build-tower-ui.png', | ||
' | '再生投影器': 'Block-regen-projector-ui.png', | ||
' | '震爆塔': 'Block-shockwave-tower-ui.png', | ||
' | '护盾投影器': 'Block-shield-projector-ui.png', | ||
' | '大型护盾投影器': 'Block-large-shield-projector-ui.png', | ||
' | '装甲管道': 'Block-armored-duct-ui.png', | ||
' | '溢流管道': 'Block-overflow-duct-ui.png', | ||
' | '反向溢流管': 'Block-underflow-duct-ui.png', | ||
' | '管道装卸器': 'Block-duct-unloader-ui.png', | ||
' | '合金传送带': 'Block-surge-conveyor-ui.png', | ||
' | '合金路由器': 'Block-surge-router-ui.png', | ||
' | '单位物流装载器': 'Block-unit-cargo-loader-ui.png', | ||
' | '单位物流卸载点': 'Block-unit-cargo-unload-point-ui.png', | ||
' | '强化泵': 'Block-reinforced-pump-ui.png', | ||
' | '强化导管': 'Block-reinforced-conduit-ui.png', | ||
' | '强化流体交叉器': 'Block-reinforced-liquid-junction-ui.png', | ||
' | '强化流体带桥': 'Block-reinforced-bridge-conduit-ui.png', | ||
' | '强化流体路由器': 'Block-reinforced-liquid-router-ui.png', | ||
' | '强化流体容器': 'Block-reinforced-liquid-container-ui.png', | ||
' | '强化流体储罐': 'Block-reinforced-liquid-tank-ui.png', | ||
' | '激光节点': 'Block-beam-node-ui.png', | ||
' | '激光塔': 'Block-beam-tower-ui.png', | ||
' | '激光连接器': 'Block-beam-link-ui.png', | ||
' | '涡轮冷凝器': 'Block-turbine-condenser-ui.png', | ||
' | '化学燃烧室': 'Block-chemical-combustion-chamber-ui.png', | ||
' | '热解发生器': 'Block-pyrolysis-generator-ui.png', | ||
' | '排气冷凝器': 'Block-vent-condenser-ui.png', | ||
' | '墙壁粉碎机': 'Block-cliff-crusher-ui.png', | ||
' | '高级墙壁粉碎机': 'Block-large-cliff-crusher-ui.png', | ||
' | '等离子钻机': 'Block-plasma-bore-ui.png', | ||
' | '大型等离子钻机': 'Block-large-plasma-bore-ui.png', | ||
' | '冲击钻头': 'Block-impact-drill-ui.png', | ||
' | '爆裂钻头': 'Block-eruption-drill-ui.png', | ||
' | '城堡核心': 'Block-core-citadel-ui.png', | ||
' | '堡垒核心': 'Block-core-bastion-ui.png', | ||
' | '卫城核心': 'Block-core-acropolis-ui.png', | ||
' | '强化容器': 'Block-reinforced-container-ui.png', | ||
' | '强化仓库': 'Block-reinforced-vault-ui.png', | ||
' | '撕裂': 'Block-ripper-ui.png', | ||
' | '升华': 'Block-sublimate-ui.png', | ||
' | '泰坦': 'Block-titan-ui.png', | ||
' | '驱离': 'Block-disperse-ui.png', | ||
' | '劫难': 'Block-afflict-ui.png', | ||
' | '光辉': 'Block-lustre-ui.png', | ||
' | '创伤': 'Block-scathe-ui.png', | ||
' | '坦克重构厂': 'Block-tank-refabricator-ui.png', | ||
' | '机甲重构厂': 'Block-mech-refabricator-ui.png', | ||
' | '飞船重构厂': 'Block-ship-refabricator-ui.png', | ||
' | '坦克组装厂': 'Block-tank-assembler-ui.png', | ||
' | '飞船组装厂': 'Block-ship-assembler-ui.png', | ||
' | '机甲组装厂': 'Block-mech-assembler-ui.png', | ||
' | '强化载荹传送带': 'Block-reinforced-payload-conveyor-ui.png', | ||
' | '强化载荹路由器': 'Block-reinforced-payload-router-ui.png', | ||
' | '载荹质量驱动器': 'Block-payload-mass-driver-ui.png', | ||
' | '解构器': 'Block-deconstructor-ui.png', | ||
' | '画板': 'Block-canvas-ui.png', | ||
' | '世界处理器': 'Block-world-processor-ui.png', | ||
' | '世界内存元': 'Block-world-cell-ui.png', | ||
' | '坦克制造厂': 'Block-tank-fabricator-ui.png', | ||
' | '机甲制造厂': 'Block-mech-fabricator-ui.png', | ||
' | '飞船制造厂': 'Block-ship-fabricator-ui.png', | ||
' | '高级再重构工厂': 'Block-prime-refabricator-ui.png', | ||
' | '单位维修塔': 'Block-unit-repair-tower-ui.png', | ||
' | '扩散': 'Block-diffuse-ui.png', | ||
' | '基本装配厂模块': 'Block-basic-assembler-module-ui.png', | ||
' | '天谦': 'Block-smite-ui.png', | ||
' | '魔灵': 'Block-malign-ui.png', | ||
' | '通量反应堆': 'Block-flux-reactor-ui.png', | ||
' | '瘤变反应堆': 'Block-neoplasia-reactor-ui.png', | ||
' | '开关': 'Block-switch-ui.png', | ||
' | '微型处理器': 'Block-micro-processor-ui.png', | ||
' | '逻辑处理器': 'Block-logic-processor-ui.png', | ||
' | '超核处理器': 'Block-hyper-processor-ui.png', | ||
' | '逻辑显示屏': 'Block-logic-display-ui.png', | ||
' | '大型逻辑显示屏': 'Block-large-logic-display-ui.png', | ||
' | '逻辑显示单元': 'Block-tile-logic-display-ui.png', | ||
' | '内存元': 'Block-memory-cell-ui.png', | ||
' | '内存库': 'Block-memory-bank-ui.png', | ||
' | '草地': 'Block-grass-ui.png', | ||
' | '矿渣液': 'Block-molten-slag-ui.png', | ||
//' | //'冷冻液': 'Block-pooled-cryofluid-ui.png', 这是地板!ai都不看重复的吗 | ||
' | '太空': 'Block-space-ui.png', | ||
' | '盐碱地': 'Block-salt-ui.png', | ||
' | '盐墙': 'Block-salt-wall-ui.png', | ||
' | '鹏卵石': 'Block-pebbles-ui.png', | ||
' | '卷须': 'Block-tendrils-ui.png', | ||
' | '沙墙': 'Block-sand-wall-ui.png', | ||
' | '孢子树': 'Block-spore-pine-ui.png', | ||
' | '孢子墙': 'Block-spore-wall-ui.png', | ||
' | '石块': 'Block-stone-ui.png', | ||
' | '雪石块': 'Block-snow-boulder-ui.png', | ||
' | '雪树': 'Block-snow-pine-ui.png', | ||
' | '页岩地': 'Block-shale-ui.png', | ||
' | '页岩石块': 'Block-shale-boulder-ui.png', | ||
' | '芜藻地': 'Block-moss-ui.png', | ||
' | '灌木丛': 'Block-shrubs-ui.png', | ||
' | '孢子芜藻地': 'Block-spore-moss-ui.png', | ||
' | '页岩墙': 'Block-shale-wall-ui.png', | ||
' | '废墙': 'Block-scrap-wall-ui.png', | ||
' | '大型废墙': 'Block-scrap-wall-large-ui.png', | ||
' | '巨型废墙': 'Block-scrap-wall-huge-ui.png', | ||
' | '超巨型废墙': 'Block-scrap-wall-gigantic-ui.png', | ||
' | '推进器残骵': 'Block-thruster-ui.png', | ||
' | '深水': 'Block-deep-water-ui.png', | ||
//' | //'水': 'Block-shallow-water-ui.png', 这是地板!ai都不看重复的吗? | ||
' | '污水': 'Block-tainted-water-ui.png', | ||
' | '深污水': 'Block-deep-tainted-water-ui.png', | ||
' | '黑沙污水': 'Block-darksand-tainted-water-ui.png', | ||
' | '石油': 'Block-tar-ui.png', | ||
' | '石头': 'Block-stone-ui.png', | ||
' | '沙子': 'Block-sand-floor-ui.png', | ||
' | '黑沙': 'Block-darksand-ui.png', | ||
' | '冰': 'Block-ice-ui.png', | ||
' | '雪': 'Block-snow-ui.png', | ||
' | '陶石坑': 'Block-crater.png', | ||
' | '浅滩': 'Block-shallow-water-ui.png', | ||
' | '黑沙浅滩': 'Block-darksand-water-ui.png', | ||
' | '焦土': 'Block-scorch-ui.png', | ||
' | '安山岩': 'Block-dacite-ui.png', | ||
' | '流纹岩': 'Block-rhyolite-ui.png', | ||
' | '安山岩墙': 'Block-dacite-wall-ui.png', | ||
' | '安山石块': 'Block-dacite-boulder-ui.png', | ||
' | '冰雪地': 'Block-ice-snow-ui.png', | ||
' | '石墙': 'Block-stone-wall-ui.png', | ||
' | '冰墙': 'Block-ice-wall-ui.png', | ||
' | '雪墙': 'Block-snow-wall-ui.png', | ||
' | '沙丘岩': 'Block-dune-wall-ui.png', | ||
' | '松树': 'Block-pine-ui.png', | ||
' | '泥土': 'Block-dirt-ui.png', | ||
' | '泥土墙': 'Block-dirt-wall-ui.png', | ||
' | '泥巴': 'Block-mud-ui.png', | ||
' | '枯萎的白树': 'Block-white-tree-dead-ui.png', | ||
' | '白树': 'Block-white-tree-ui.png', | ||
' | '孢子簇': 'Block-spore-cluster-ui.png', | ||
' | '金属地板1': 'Block-metal-floor-ui.png', | ||
' | '金属地板2': 'Block-metal-floor-2-ui.png', | ||
' | '金属地板3': 'Block-metal-floor-3-ui.png', | ||
' | '金属地板4': 'Block-metal-floor-4-ui.png', | ||
' | '金属地板5': 'Block-metal-floor-5-ui.png', | ||
' | '损坏的金属地板': 'Block-metal-floor-damaged-ui.png', | ||
' | '金属地基1': 'Block-metal-tiles-1-ui.png', | ||
' | '金属地基2': 'Block-metal-tiles-2-ui.png', | ||
' | '金属地基3': 'Block-metal-tiles-3-ui.png', | ||
' | '金属地基4': 'Block-metal-tiles-4-ui.png', | ||
' | '金属地基5': 'Block-metal-tiles-5-ui.png', | ||
' | '金属地基6': 'Block-metal-tiles-6-ui.png', | ||
' | '金属地基7': 'Block-metal-tiles-7-ui.png', | ||
' | '金属地基8': 'Block-metal-tiles-8-ui.png', | ||
' | '金属地基9': 'Block-metal-tiles-9-ui.png', | ||
' | '金属地基10': 'Block-metal-tiles-10-ui.png', | ||
' | '金属地基11': 'Block-metal-tiles-11-ui.png', | ||
' | '金属地基12': 'Block-metal-tiles-12-ui.png', | ||
' | '金属地基13': 'Block-metal-tiles-13-ui.png', | ||
' | '金属墙1': 'Block-metal-wall-1-ui.png', | ||
' | '金属墙2': 'Block-metal-wall-2-ui.png', | ||
' | '金属墙3': 'Block-metal-wall-3-ui.png', | ||
' | '染色地板': 'Block-colored-floor-ui.png', | ||
' | '染色墙壈': 'Block-colored-wall-ui.png', | ||
' | '标识贴片': 'Block-character-overlay-ui.png', | ||
' | '标识贴片(白色)': 'Block-character-overlay-white-ui.png', | ||
' | '符文贴片': 'Block-rune-overlay-ui.png', | ||
' | '符文贴片(红队)': 'Block-rune-overlay-crux-ui.png', | ||
' | '暗面板1': 'Block-dark-panel-1-ui.png', | ||
' | '暗面板2': 'Block-dark-panel-2-ui.png', | ||
' | '暗面板3': 'Block-dark-panel-3-ui.png', | ||
' | '暗面板4': 'Block-dark-panel-4-ui.png', | ||
' | '暗面板5': 'Block-dark-panel-5-ui.png', | ||
' | '暗面板6': 'Block-dark-panel-6-ui.png', | ||
' | '暗金属': 'Block-dark-metal-ui.png', | ||
' | '玄武岩': 'Block-basalt-ui.png', | ||
' | '灼热岩石': 'Block-hotrock-ui.png', | ||
' | '熔融岩石': 'Block-magmarock-ui.png', | ||
' | '铜墙': 'Block-copper-wall-ui.png', | ||
' | '大型铜墙': 'Block-copper-wall-large-ui.png', | ||
' | '钛墙': 'Block-titanium-wall-ui.png', | ||
' | '大型钛墙': 'Block-titanium-wall-large-ui.png', | ||
' | '塑钢墙': 'Block-plastanium-wall-ui.png', | ||
' | '大型塑钢墙': 'Block-plastanium-wall-large-ui.png', | ||
' | '相织布墙': 'Block-phase-wall-ui.png', | ||
' | '大型相织布墙': 'Block-phase-wall-large-ui.png', | ||
' | '钱墙': 'Block-thorium-wall-ui.png', | ||
' | '大型钱墙': 'Block-thorium-wall-large-ui.png', | ||
' | '门': 'Block-door-ui.png', | ||
' | '大门': 'Block-door-large-ui.png', | ||
' | '塞普罗': 'Planet-serpulo.png', | ||
' | '埃里克尔': 'Planet-erekir.png', | ||
' | '太阳': 'Sun.png', | ||
' | '降雨': 'ohno.png', | ||
' | '降雪': 'ohno.png', | ||
' | '沙尘暴': 'ohno.png', | ||
' | '孢子风暴': 'ohno.png', | ||
' | '雾': 'ohno.png', | ||
' | '燃烧': 'Status-burning-ui.png', | ||
' | '冻结': 'Status-freezing-ui.png', | ||
' | '潮湿': 'Status-wet-ui.png', | ||
' | '泥污': 'Status-muddy-ui.png', | ||
' | '熔化': 'Status-melting-ui.png', | ||
' | '弱化': 'Status-slow-ui.png', | ||
' | '麻痹': 'Status-electrified-ui.png', | ||
' | '孢子减速': 'Status-spore-slowed-ui.png', | ||
' | '油浸': 'Status-tarred-ui.png', | ||
' | '过载': 'Status-overdrive-ui.png', | ||
' | '超频': 'Status-overclock-ui.png', | ||
' | '电击': 'Status-shocked-ui.png', | ||
' | '爆炸': 'Status-blasted-ui.png', | ||
' | '腐蚀': 'Status-corroded-ui.png', | ||
' | '静止': 'Status-unmoving-ui.png', | ||
'Boss': 'Status-boss-ui.png' | 'Boss': 'Status-boss-ui.png' | ||
| 第1,887行: | 第1,887行: | ||
btn.type = 'button'; | btn.type = 'button'; | ||
btn.className = 'mw-ui-button mw-ui-progressive'; | btn.className = 'mw-ui-button mw-ui-progressive'; | ||
btn.textContent = ' | btn.textContent = '一键配图标'; | ||
var undo = document.createElement('button'); | var undo = document.createElement('button'); | ||
undo.type = 'button'; | undo.type = 'button'; | ||
undo.className = 'mw-ui-button'; | undo.className = 'mw-ui-button'; | ||
undo.textContent = ' | undo.textContent = '撤销配图标'; | ||
undo.disabled = true; | undo.disabled = true; | ||
| 第1,898行: | 第1,898行: | ||
note.style.opacity = '0.75'; | note.style.opacity = '0.75'; | ||
note.style.fontSize = '12px'; | note.style.fontSize = '12px'; | ||
note.textContent = ' | note.textContent = '只处理[[...]]链接'; | ||
host.appendChild(btn); | host.appendChild(btn); | ||
| 第1,911行: | 第1,911行: | ||
var result = convertWikitext(current); | var result = convertWikitext(current); | ||
if (!result.changed) { | if (!result.changed) { | ||
alert(' | alert('没有可替换的链接'); | ||
return; | return; | ||
} | } | ||
| 第1,917行: | 第1,917行: | ||
undo.disabled = false; | undo.disabled = false; | ||
ta.value = result.text; | ta.value = result.text; | ||
alert(' | alert('已插入 ' + String(result.changed) + ' 个图标'); | ||
}); | }); | ||
undo.addEventListener('click', function () { | undo.addEventListener('click', function () { | ||
if (!backup) { | if (!backup) { | ||
alert(' | alert('没有备份'); | ||
return; | return; | ||
} | } | ||
| 第1,928行: | 第1,928行: | ||
backup = ''; | backup = ''; | ||
undo.disabled = true; | undo.disabled = true; | ||
alert(' | alert('已撤销'); | ||
}); | }); | ||
} | } | ||
2026年2月22日 (日) 09:20的版本
/* MediaWiki:Common.js */
(function () {
'use strict';
function fallbackCopy(text) {
if (!window.jQuery) return;
var $ = window.jQuery;
var $temp = $('<textarea>');
$('body').append($temp);
$temp.val(text).select();
document.execCommand('copy');
$temp.remove();
alert('复制成功!');
}
// 点击按钮复制内容:<button class="copy-button" data-text="...">复制</button>
if (window.jQuery) {
window.jQuery(function ($) {
$(document).on('click', '.copy-button', function () {
var text = $(this).attr('data-text') || '';
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function () {
alert('复制成功!');
}, function () {
fallbackCopy(text);
});
} else {
fallbackCopy(text);
}
});
});
}
// Timeless:把 Sidebar 里以 "-- " 开头的条目变成可折叠子项
mw.loader.using(['mediawiki.util'], function () {
if (mw.config.get('skin') !== 'timeless') return;
function initNavTree() {
var siteNav = document.getElementById('mw-site-navigation');
if (!siteNav) return;
var pNav = siteNav.querySelector('#p-navigation');
if (!pNav) return;
var root = pNav.querySelector('.mw-portlet-body > ul') ||
pNav.querySelector('ul');
if (!root) return;
if (root.getAttribute('data-mdtNav') === '1') return;
root.setAttribute('data-mdtNav', '1');
var KEY = 'mdtNavTreeOpen';
var store = {};
try {
store = JSON.parse(localStorage.getItem(KEY) || '{}');
} catch (e) {
store = {};
}
function getKey(li) {
if (li && li.id) return li.id;
var a = li ? li.querySelector('a') : null;
return a ? (a.getAttribute('href') || '') : '';
}
function setStored(li, open) {
var k = getKey(li);
if (!k) return;
store[k] = open;
try {
localStorage.setItem(KEY, JSON.stringify(store));
} catch (e) {}
}
function setOpen(li, open, persist) {
li.classList.toggle('mdtNavOpen', open);
if (persist) setStored(li, open);
}
function ensureGroup(li) {
li.classList.add('mdtNavGroup');
var sub = li.querySelector('ul.mdtNavSublist');
if (!sub) {
sub = document.createElement('ul');
sub.className = 'mdtNavSublist';
li.appendChild(sub);
}
var btn = li.querySelector('button.mdtNavToggle');
if (!btn) {
btn = document.createElement('button');
btn.type = 'button';
btn.className = 'mdtNavToggle';
btn.setAttribute('aria-label', '展开/收起');
btn.setAttribute('aria-expanded', 'false');
li.insertBefore(btn, sub);
btn.addEventListener('click', function (ev) {
ev.preventDefault();
ev.stopPropagation();
var isOpen = li.classList.contains('mdtNavOpen');
setOpen(li, !isOpen, true);
btn.setAttribute('aria-expanded', String(!isOpen));
});
}
var k = getKey(li);
if (store[k] === true) {
li.classList.add('mdtNavOpen');
btn.setAttribute('aria-expanded', 'true');
}
return sub;
}
var items = Array.prototype.slice.call(root.children);
var lastAtDepth = [];
for (var i = 0; i < items.length; i++) {
var li = items[i];
if (!li || li.tagName !== 'LI') continue;
var a = li.querySelector('a');
if (!a) continue;
var raw = (a.textContent || '').trim();
var m = raw.match(/^(-{2,})\s*(.*)$/);
var depth = 0;
if (m) {
depth = Math.min(Math.floor(m[1].length / 2), 3);
a.textContent = m[2];
}
li.classList.add('mdtNavItem');
if (depth > 0 && lastAtDepth[depth - 1]) {
li.classList.add('mdtNavSubItem');
li.classList.add('mdtNavDepth' + String(depth));
var sublist = ensureGroup(lastAtDepth[depth - 1]);
sublist.appendChild(li);
} else {
depth = 0;
}
lastAtDepth[depth] = li;
lastAtDepth.length = depth + 1;
}
// 当前页面高亮 + 自动展开父级
var current = (mw.config.get('wgPageName') || '').replace(/ /g, '_');
var links = pNav.querySelectorAll('a');
function titleFromHref(href) {
var t = mw.util.getParamValue('title', href);
if (t) return t.replace(/ /g, '_');
var mark = '/index.php/';
var pos = href.indexOf(mark);
if (pos !== -1) {
return decodeURIComponent(href.slice(pos + mark.length))
.replace(/ /g, '_');
}
return '';
}
for (var j = 0; j < links.length; j++) {
var href = links[j].getAttribute('href') || '';
var page = titleFromHref(href);
if (page && page === current) {
links[j].classList.add('mdtNavActive');
var n = links[j].parentNode;
while (n && n !== root) {
if (n.tagName === 'LI' && n.classList.contains('mdtNavGroup')) {
setOpen(n, true, false);
var btn = n.querySelector('button.mdtNavToggle');
if (btn) btn.setAttribute('aria-expanded', 'true');
}
n = n.parentNode;
}
break;
}
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initNavTree);
} else {
initNavTree();
}
});
// 可折叠标题:在标题旁边加一个展开/收起按钮
// 用法:把任意标题写成:== 战役区块 <span class="mdtFold"></span> ==
// 默认收起:== 战役区块 <span class="mdtFold mdtFoldClosed"></span> ==
mw.loader.using(['mediawiki.util'], function () {
var skin = String(mw.config.get('skin') || '').toLowerCase();
if (skin !== 'timeless') return;
var action = String(mw.config.get('wgAction') || 'view').toLowerCase();
if (action === 'edit' || action === 'submit') return;
function findHeading(node) {
while (node && node !== document.body) {
if (node.nodeType === 1 && /^H[1-6]$/.test(node.tagName)) return node;
node = node.parentNode;
}
return null;
}
var KEY = 'mdtFoldSections';
var store = {};
try {
store = JSON.parse(localStorage.getItem(KEY) || '{}');
} catch (e) {
store = {};
}
function saveStore() {
try {
localStorage.setItem(KEY, JSON.stringify(store));
} catch (e) {}
}
function getHeadingBlock(headingEl) {
if (!headingEl || !headingEl.parentElement) return headingEl;
// MediaWiki 新版可能会把 h2 包在 <div class="mw-heading"> 里。
// 如果不处理这个 wrapper,折叠只会影响 wrapper 内部(看起来“没效果”)。
var p = headingEl.parentElement;
if (p.classList && p.classList.contains('mw-heading')) return p;
return headingEl;
}
function getHeadingLevelFromNode(node) {
if (!node || node.nodeType !== 1) return null;
if (/^H[1-6]$/.test(node.tagName)) {
return parseInt(String(node.tagName).slice(1), 10) || 6;
}
if (node.classList && node.classList.contains('mw-heading')) {
var h = node.querySelector('h1,h2,h3,h4,h5,h6');
if (h && /^H[1-6]$/.test(h.tagName)) {
return parseInt(String(h.tagName).slice(1), 10) || 6;
}
}
return null;
}
function initFoldSections(root) {
var content = root || document.getElementById('mw-content-text') ||
document.querySelector('.mw-parser-output') ||
document.body;
if (!content) return;
var nodes = [];
var markers = content.querySelectorAll('.mdtFold');
var headingNodes = content.querySelectorAll('h1.mdtFoldHeading,h2.mdtFoldHeading,h3.mdtFoldHeading,h4.mdtFoldHeading,h5.mdtFoldHeading,h6.mdtFoldHeading');
for (var h = 0; h < headingNodes.length; h++) nodes.push(headingNodes[h]);
for (var m = 0; m < markers.length; m++) nodes.push(markers[m]);
if (!nodes.length) return;
for (var i = 0; i < nodes.length; i++) {
(function (nodeOrMarker) {
var marker = null;
var heading = null;
if (nodeOrMarker && nodeOrMarker.nodeType === 1 && /^H[1-6]$/.test(nodeOrMarker.tagName)) {
heading = nodeOrMarker;
} else {
marker = nodeOrMarker;
heading = findHeading(marker);
}
if (!heading) return;
// 兼容:如果是通过 h2.mdtFoldHeading 触发,但里面也有 span.mdtFold,
// 也要把 marker 当作触发点,这样可以读取默认收起并移除 marker。
if (!marker) {
marker = heading.querySelector('.mdtFold');
}
var headingBlock = getHeadingBlock(heading);
if (!headingBlock) return;
if (headingBlock.getAttribute('data-mdtFoldInit') === '1') return;
headingBlock.setAttribute('data-mdtFoldInit', '1');
var level = parseInt(String(heading.tagName).slice(1), 10) || 2;
var headline = heading.querySelector('.mw-headline');
// Body: 优先折叠“紧跟着”的图标网格(你这个场景就是 h2 + .mdtIconGrid)。
// 也支持手动标记:<div class="mdtFoldBody">...</div>
var body = null;
var nextEl = headingBlock.nextElementSibling;
if (nextEl && nextEl.classList) {
if (nextEl.classList.contains('mdtFoldBody') || nextEl.classList.contains('mdtIconGrid')) {
body = nextEl;
body.classList.add('mdtFoldBody');
}
}
// 自动模式:把标题后面直到下一个“同级或更高级标题”的所有节点包起来。
if (!body) {
body = document.createElement('div');
body.className = 'mdtFoldBody';
var node = headingBlock.nextSibling;
while (node) {
var next = node.nextSibling;
var nodeLevel = getHeadingLevelFromNode(node);
if (nodeLevel !== null && nodeLevel <= level) break;
body.appendChild(node);
node = next;
}
headingBlock.parentNode.insertBefore(body, node);
}
// Toggle button
var btn = document.createElement('button');
btn.type = 'button';
btn.className = 'mdtFoldToggle';
btn.setAttribute('aria-label', '展开/收起');
btn.setAttribute('aria-expanded', 'true');
btn.title = '展开/收起';
btn.textContent = '▾';
// Inline style fallback: in case Timeless.css is not loaded yet.
btn.style.width = '1.6rem';
btn.style.height = '1.6rem';
btn.style.marginLeft = '0.25rem';
btn.style.border = '0';
btn.style.padding = '0';
btn.style.borderRadius = '10px';
btn.style.display = 'inline-flex';
btn.style.alignItems = 'center';
btn.style.justifyContent = 'center';
btn.style.background = 'rgba(0, 175, 137, 0.10)';
btn.style.color = 'var(--mdtBrand)';
btn.style.cursor = 'pointer';
btn.style.fontFamily = 'inherit';
btn.style.fontSize = '16px';
btn.style.fontWeight = '700';
btn.style.lineHeight = '1';
btn.style.boxShadow = 'none';
btn.style.outline = 'none';
btn.style.appearance = 'none';
btn.style.webkitAppearance = 'none';
if (headline) {
headline.classList.add('mdtFoldHeadline');
headline.appendChild(btn);
} else {
var wrap = document.createElement('span');
wrap.className = 'mdtFoldHeadline';
while (heading.firstChild) {
wrap.appendChild(heading.firstChild);
}
heading.appendChild(wrap);
wrap.appendChild(btn);
headline = wrap;
}
// Marker/heading default state
var defaultClosed = false;
if (marker && marker.classList && marker.classList.contains('mdtFoldClosed')) {
defaultClosed = true;
}
if (heading.classList && heading.classList.contains('mdtFoldClosed')) {
defaultClosed = true;
}
// Remove marker to avoid extra spacing
if (marker && marker.parentNode) marker.parentNode.removeChild(marker);
var page = (mw.config.get('wgPageName') || '').replace(/ /g, '_');
var id = '';
if (headline && headline.id) id = headline.id;
if (!id) id = (heading.textContent || '').trim();
var storageKey = page + '::' + id;
function setCollapsed(collapsed, persist) {
headingBlock.classList.toggle('mdtFoldCollapsed', collapsed);
btn.setAttribute('aria-expanded', String(!collapsed));
btn.textContent = collapsed ? '▸' : '▾';
if (body) {
body.classList.toggle('mdtFoldHidden', collapsed);
// Ensure it works even if CSS is missing/cached.
body.style.display = collapsed ? 'none' : '';
}
if (persist) {
store[storageKey] = collapsed;
saveStore();
}
}
var collapsed = false;
if (typeof store[storageKey] === 'boolean') {
collapsed = store[storageKey];
} else if (defaultClosed) {
collapsed = true;
}
setCollapsed(collapsed, false);
btn.addEventListener('click', function (ev) {
ev.preventDefault();
ev.stopPropagation();
var isCollapsed = headingBlock.classList.contains('mdtFoldCollapsed');
setCollapsed(!isCollapsed, true);
});
})(nodes[i]);
}
}
function runOnPage() {
initFoldSections(document.getElementById('mw-content-text') ||
document.querySelector('.mw-parser-output') ||
document.body);
}
// MediaWiki 推荐:内容渲染/替换后触发(兼容预览、部分皮肤/插件)。
if (mw.hook && window.jQuery) {
mw.hook('wikipage.content').add(function ($content) {
initFoldSections($content && $content[0] ? $content[0] : null);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', runOnPage);
} else {
runOnPage();
}
});
})();
(function () {
'use strict';
/* Timeless: 左/右侧栏抽屉 + 首页按钮 */
mw.loader.using(['mediawiki.util'], function () {
if (mw.config.get('skin') !== 'timeless') return;
function onReady(fn) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', fn);
} else {
fn();
}
}
var ICON_HOME =
'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>';
var ICON_MENU =
'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"/></svg>';
var ICON_GEAR =
'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M19.14 12.94c.04-.31.06-.63.06-.94s-.02-.63-.06-.94l2.03-1.58a.5.5 0 0 0 .12-.64l-1.92-3.32a.5.5 0 0 0-.6-.22l-2.39.96c-.5-.38-1.04-.7-1.63-.94l-.36-2.54A.5.5 0 0 0 13.9 2h-3.8a.5.5 0 0 0-.49.42l-.36 2.54c-.59.24-1.13.56-1.63.94l-2.39-.96a.5.5 0 0 0-.6.22L2.71 8.48a.5.5 0 0 0 .12.64l2.03 1.58c-.04.31-.06.63-.06.94s.02.63.06.94L2.83 14.52a.5.5 0 0 0-.12.64l1.92 3.32c.13.22.39.31.6.22l2.39-.96c.5.38 1.04.7 1.63.94l.36 2.54c.05.24.25.42.49.42h3.8c.24 0 .44-.18.49-.42l.36-2.54c.59-.24 1.13-.56 1.63-.94l2.39.96c.22.09.47 0 .6-.22l1.92-3.32a.5.5 0 0 0-.12-.64l-2.03-1.58zM12 15.5A3.5 3.5 0 1 1 12 8.5a3.5 3.5 0 0 1 0 7z"/></svg>';
function wrapIcon(svg) {
var span = document.createElement('span');
span.className = 'mdtDockIcon';
span.innerHTML = svg;
return span;
}
onReady(function () {
if (document.getElementById('mdtDockLeft')) return;
var siteNav = document.getElementById('mw-site-navigation');
var relatedNav = document.getElementById('mw-related-navigation');
if (!siteNav && !relatedNav) return;
document.body.classList.add('mdtDockEnabled');
var backdrop = document.createElement('div');
backdrop.id = 'mdtDockBackdrop';
function syncBackdrop() {
var open =
document.body.classList.contains('mdtDockNavOpen') ||
document.body.classList.contains('mdtDockToolsOpen');
backdrop.classList.toggle('is-active', open);
}
function closeAll() {
document.body.classList.remove('mdtDockNavOpen', 'mdtDockToolsOpen');
syncBackdrop();
}
backdrop.addEventListener('click', closeAll);
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') closeAll();
});
// 左侧:홈 + 汉堡
var left = document.createElement('div');
left.id = 'mdtDockLeft';
var home = document.createElement('a');
home.className = 'mdtDockBtn';
home.href = mw.util.getUrl('首页');
home.title = '首页';
home.setAttribute('aria-label', '首页');
home.appendChild(wrapIcon(ICON_HOME));
left.appendChild(home);
if (siteNav) {
var navBtn = document.createElement('button');
navBtn.type = 'button';
navBtn.className = 'mdtDockBtn';
navBtn.title = '导航';
navBtn.setAttribute('aria-label', '导航');
navBtn.appendChild(wrapIcon(ICON_MENU));
navBtn.addEventListener('click', function () {
var nowOpen = document.body.classList.toggle('mdtDockNavOpen');
if (nowOpen) document.body.classList.remove('mdtDockToolsOpen');
syncBackdrop();
});
left.appendChild(navBtn);
}
// 右侧:齿轮
var right = document.createElement('div');
right.id = 'mdtDockRight';
if (relatedNav) {
var toolsBtn = document.createElement('button');
toolsBtn.type = 'button';
toolsBtn.className = 'mdtDockBtn';
toolsBtn.title = '页面工具';
toolsBtn.setAttribute('aria-label', '页面工具');
toolsBtn.appendChild(wrapIcon(ICON_GEAR));
toolsBtn.addEventListener('click', function () {
var nowOpen = document.body.classList.toggle('mdtDockToolsOpen');
if (nowOpen) document.body.classList.remove('mdtDockNavOpen');
syncBackdrop();
});
left.appendChild(toolsBtn);
}
document.body.appendChild(backdrop);
document.body.appendChild(left);
document.body.appendChild(backdrop);
document.body.appendChild(left);
document.body.appendChild(right);
syncBackdrop();
});
});
})();
(function () {
'use strict';
function isTimeless() {
try {
return String(mw.config.get('skin') || '').toLowerCase() === 'timeless';
} catch (e) {
return false;
}
}
function isViewMode() {
var a = String(mw.config.get('wgAction') || 'view').toLowerCase();
return a === 'view';
}
function isMobileUA() {
var ua = String(navigator.userAgent || '');
return /Mobi|Android|iPhone|iPad|iPod/i.test(ua);
}
function normalizeText(text) {
return String(text || '')
.replace(/\s+/g, ' ')
.replace(/[▸▾]/g, '')
.trim();
}
function collectGroups(root) {
var nodes = root.querySelectorAll('h2, h3');
var groups = [];
var current = null;
for (var i = 0; i < nodes.length; i++) {
var h = nodes[i];
if (!h) continue;
var id = h.id || '';
if (!id) continue;
var text = normalizeText(h.textContent);
if (!text) continue;
if (h.tagName === 'H2') {
current = { id: id, text: text, children: [] };
groups.push(current);
} else {
if (!current) continue;
current.children.push({ id: id, text: text });
}
}
return groups;
}
function flattenIds(groups) {
var ids = [];
for (var i = 0; i < groups.length; i++) {
ids.push(groups[i].id);
var children = groups[i].children || [];
for (var j = 0; j < children.length; j++) {
ids.push(children[j].id);
}
}
return ids;
}
function buildPanel(groups) {
var wrap = document.createElement('div');
wrap.id = 'mdtFloatToc';
wrap.className = 'mdtFloatToc';
wrap.innerHTML =
"<button type='button' class='mdtFloatTocBtn' aria-label='目录'>≡</button>" +
"<div class='mdtFloatTocPanel' role='dialog' aria-label='目录'>" +
" <div class='mdtFloatTocHead'>" +
" <button type='button' class='mdtFloatTocTop'><span aria-hidden='true'>↑</span>返回顶部</button>" +
" <div class='mdtFloatTocTitle'>目录</div>" +
" <button type='button' class='mdtFloatTocClose' aria-label='关闭'>✕</button>" +
" </div>" +
" <ul class='mdtFloatTocList'></ul>" +
"</div>";
var ul = wrap.querySelector('.mdtFloatTocList');
for (var i = 0; i < groups.length; i++) {
(function (g) {
var li = document.createElement('li');
li.className = 'mdtFloatTocItem mdtFloatTocGroup';
var row = document.createElement('div');
row.className = 'mdtFloatTocRow';
var a = document.createElement('a');
a.href = '#' + encodeURIComponent(g.id).replace(/%2F/g, '/');
a.textContent = g.text;
row.appendChild(a);
if (g.children && g.children.length) {
var btn = document.createElement('button');
btn.type = 'button';
btn.className = 'mdtFloatTocGroupToggle';
btn.setAttribute('aria-label', '展开/收起');
btn.setAttribute('aria-expanded', 'false');
btn.textContent = '▸';
row.appendChild(btn);
var sub = document.createElement('ul');
sub.className = 'mdtFloatTocSublist';
for (var j = 0; j < g.children.length; j++) {
var c = g.children[j];
var cli = document.createElement('li');
cli.className = 'mdtFloatTocItem';
cli.innerHTML = "<a href='#" + encodeURIComponent(c.id).replace(/%2F/g, '/') + "'>" +
mw.html.escape(c.text) + "</a>";
sub.appendChild(cli);
}
li.appendChild(row);
li.appendChild(sub);
btn.addEventListener('click', function (ev) {
ev.preventDefault();
ev.stopPropagation();
var open = li.classList.toggle('mdtFloatTocGroupOpen');
btn.setAttribute('aria-expanded', String(open));
btn.textContent = open ? '▾' : '▸';
});
} else {
li.appendChild(row);
}
ul.appendChild(li);
})(groups[i]);
}
function openPanel(open) {
wrap.classList.toggle('mdtFloatTocOpen', open);
}
wrap.querySelector('.mdtFloatTocBtn').addEventListener('click', function () {
openPanel(true);
});
wrap.querySelector('.mdtFloatTocClose').addEventListener('click', function () {
openPanel(false);
});
wrap.querySelector('.mdtFloatTocTop').addEventListener('click', function () {
openPanel(false);
window.scrollTo({ top: 0, behavior: 'smooth' });
});
// Click a toc item -> close + smooth scroll
wrap.addEventListener('click', function (ev) {
var a = ev.target && ev.target.closest ? ev.target.closest('a') : null;
if (!a) return;
var href = a.getAttribute('href') || '';
if (href.charAt(0) !== '#') return;
ev.preventDefault();
openPanel(false);
var id = decodeURIComponent(href.slice(1));
var target = document.getElementById(id);
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
history.replaceState(null, '', '#' + encodeURIComponent(id));
}
});
// Close when tapping outside
document.addEventListener('click', function (ev) {
if (!wrap.classList.contains('mdtFloatTocOpen')) return;
if (wrap.contains(ev.target)) return;
openPanel(false);
});
// Highlight active heading
var linkById = {};
var links = wrap.querySelectorAll('a');
for (var k = 0; k < links.length; k++) {
var id2 = decodeURIComponent((links[k].getAttribute('href') || '').slice(1));
linkById[id2] = links[k];
}
var ids = flattenIds(groups);
var ticking = false;
function updateActive() {
ticking = false;
var bestId = '';
var bestTop = -Infinity;
for (var i2 = 0; i2 < ids.length; i2++) {
var el = document.getElementById(ids[i2]);
if (!el) continue;
var rect = el.getBoundingClientRect();
if (rect.top <= 120 && rect.top > bestTop) {
bestTop = rect.top;
bestId = ids[i2];
}
}
for (var idKey in linkById) {
linkById[idKey].classList.toggle('mdtFloatTocActive', idKey === bestId);
}
}
window.addEventListener('scroll', function () {
if (ticking) return;
ticking = true;
window.requestAnimationFrame(updateActive);
}, { passive: true });
return wrap;
}
function ensureHeadingIds(root) {
var headings = root.querySelectorAll('h2, h3');
for (var i = 0; i < headings.length; i++) {
var h = headings[i];
if (h.id) continue;
var hl = h.querySelector('.mw-headline');
if (hl && hl.id) h.id = hl.id;
}
}
function initFloatToc($content) {
if (!isTimeless() || !isViewMode() || !isMobileUA()) return;
var content = $content && $content[0] ? $content[0] : null;
var root = content || document.querySelector('.mw-parser-output') || document.getElementById('mw-content-text');
if (!root) return;
if (document.getElementById('mdtFloatToc')) return;
ensureHeadingIds(root);
var groups = collectGroups(root);
if (!groups.length) return;
document.body.appendChild(buildPanel(groups));
}
mw.loader.using(['mediawiki.util', 'mediawiki.html']).then(function () {
if (mw.hook && window.jQuery) {
mw.hook('wikipage.content').add(initFloatToc);
}
initFloatToc(null);
});
})();
/*
MDT Float TOC (desktop: dock to top-right gutter, default open)
Paste this whole file into: MediaWiki:Common.js (very bottom)
*/
(function () {
'use strict';
var DESKTOP_MIN_WIDTH = 1000;
var GAP_PX = 12;
var FALLBACK_TOP_REM = 4.1;
function isViewMode() {
try {
return String(mw.config.get('wgAction') || 'view').toLowerCase() === 'view';
} catch (e) {
return true;
}
}
function isDesktop() {
try {
return (
window.matchMedia &&
window.matchMedia('(min-width: ' + String(DESKTOP_MIN_WIDTH) + 'px)').matches
);
} catch (e) {
return false;
}
}
function remToPx(rem) {
var fs = 16;
try {
fs = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
} catch (e) {}
return rem * fs;
}
function getDockTopPx() {
var dock = document.getElementById('mdtDockLeft') || document.getElementById('mdtDockRight');
if (dock && dock.getBoundingClientRect) {
return Math.round(dock.getBoundingClientRect().top);
}
return Math.round(remToPx(FALLBACK_TOP_REM));
}
function normalizeText(text) {
return String(text || '')
.replace(/\s+/g, ' ')
.replace(/[▸▾]/g, '')
.trim();
}
function ensureHeadingIds(root) {
var headings = root.querySelectorAll('h2, h3');
for (var i = 0; i < headings.length; i++) {
var h = headings[i];
if (!h || h.id) continue;
var hl = h.querySelector('.mw-headline');
if (hl && hl.id) h.id = hl.id;
}
}
function shouldSkipHeading(h) {
if (!h) return true;
if (!h.id) return true;
if (h.closest('#mw-site-navigation, #mw-related-navigation, .mw-portlet, .mdtRightRail')) return true;
return false;
}
function collectGroups(root) {
var nodes = root.querySelectorAll('h2, h3');
var groups = [];
var current = null;
for (var i = 0; i < nodes.length; i++) {
var h = nodes[i];
if (shouldSkipHeading(h)) continue;
var id = h.id;
var headline = h.querySelector('.mw-headline');
var text = normalizeText(headline ? headline.textContent : h.textContent);
if (!text) continue;
if (h.tagName === 'H2') {
current = { id: id, text: text, children: [] };
groups.push(current);
} else {
if (!current) continue;
current.children.push({ id: id, text: text });
}
}
return groups;
}
function flattenIds(groups) {
var ids = [];
for (var i = 0; i < groups.length; i++) {
ids.push(groups[i].id);
var children = groups[i].children || [];
for (var j = 0; j < children.length; j++) ids.push(children[j].id);
}
return ids;
}
function injectCssOnce() {
if (document.getElementById('mdtFloatTocStyle')) return;
var css = [
'#mw-content-text .mw-headline{scroll-margin-top:5rem;}',
/* wrapper (mobile default: bottom-right) */
'#mdtFloatToc{position:fixed;right:0.9rem;bottom:1.1rem;top:auto;z-index:9999;font-family:inherit;display:block !important;}',
/* open button */
'#mdtFloatToc .mdtFloatTocBtn{width:3rem;height:3rem;border-radius:999px;border:1px solid rgba(255,255,255,0.14);background:rgba(0,0,0,0.70);color:rgba(255,255,255,0.92);box-shadow:0 12px 28px rgba(0,0,0,0.28);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-weight:900;}',
'#mdtFloatToc .mdtFloatTocBtn:hover{border-color:rgba(0,207,160,0.60);box-shadow:0 12px 28px rgba(0,0,0,0.28),0 0 0 3px rgba(0,207,160,0.18);}',
'#mdtFloatToc.mdtFloatTocOpen .mdtFloatTocBtn{opacity:0;pointer-events:none;}',
/* panel (mobile default: popup) */
'#mdtFloatToc .mdtFloatTocPanel{position:absolute;right:0;bottom:3.75rem;width:min(22rem,88vw);max-height:min(70vh,34rem);overflow:auto;padding:0.85rem 0.9rem;border-radius:16px;background:rgba(36,46,45,0.92);border:1px solid rgba(255,255,255,0.14);box-shadow:0 18px 44px rgba(0,0,0,0.32);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);color:rgba(255,255,255,0.92);display:none;}',
'#mdtFloatToc.mdtFloatTocOpen .mdtFloatTocPanel{display:block;}',
/* head */
'#mdtFloatToc .mdtFloatTocHead{display:flex;align-items:center;justify-content:space-between;gap:0.75rem;padding:0 0 0.55rem 0;margin:0 0 0.6rem 0;border-bottom:1px solid rgba(255,255,255,0.10);}',
'#mdtFloatToc .mdtFloatTocTitle{font-weight:900;opacity:0.9;letter-spacing:0.06em;}',
'#mdtFloatToc .mdtFloatTocTop,#mdtFloatToc .mdtFloatTocClose{border:0;background:transparent;color:inherit;cursor:pointer;padding:0;font-family:inherit;}',
'#mdtFloatToc .mdtFloatTocTop{display:inline-flex;align-items:center;gap:0.55rem;font-weight:900;color:var(--mdtBrand2,#00cfa0);}',
'#mdtFloatToc .mdtFloatTocClose{width:2rem;height:2rem;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;background:rgba(255,255,255,0.06);}',
'#mdtFloatToc .mdtFloatTocClose:hover{background:rgba(255,255,255,0.12);}',
/* list */
'#mdtFloatToc .mdtFloatTocList{list-style:none;margin:0;padding:0 0 0 0.85rem;border-left:1px solid rgba(255,255,255,0.12);}',
'#mdtFloatToc .mdtFloatTocRow{display:flex;align-items:center;gap:0.35rem;}',
'#mdtFloatToc .mdtFloatTocItem{margin:0.18rem 0;}',
'#mdtFloatToc .mdtFloatTocItem a,#mdtFloatToc .mdtFloatTocItem a:visited{color:rgba(255,255,255,0.86);text-decoration:none;font-weight:750;display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}',
'#mdtFloatToc .mdtFloatTocItem a:hover{color:var(--mdtBrand2,#00cfa0);text-decoration:underline;}',
'#mdtFloatToc .mdtFloatTocItem a.mdtFloatTocActive{color:var(--mdtBrand2,#00cfa0);text-decoration:underline;}',
/* sub list */
'#mdtFloatToc .mdtFloatTocGroupToggle{border:0;background:rgba(255,255,255,0.06);color:rgba(255,255,255,0.80);cursor:pointer;padding:0;width:2rem;height:2rem;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;}',
'#mdtFloatToc .mdtFloatTocGroupToggle:hover{background:rgba(255,255,255,0.12);}',
'#mdtFloatToc .mdtFloatTocGroup.mdtFloatTocGroupOpen .mdtFloatTocGroupToggle{color:var(--mdtBrand2,#00cfa0);}',
'#mdtFloatToc .mdtFloatTocSublist{list-style:none;margin:0.35rem 0 0.25rem;padding:0 0 0 0.85rem;border-left:1px solid rgba(255,255,255,0.12);display:none;}',
'#mdtFloatToc .mdtFloatTocGroup.mdtFloatTocGroupOpen .mdtFloatTocSublist{display:block;}'
].join('\n');
var style = document.createElement('style');
style.id = 'mdtFloatTocStyle';
style.type = 'text/css';
style.textContent = css;
document.head.appendChild(style);
}
function applyDesktopDock(wrap) {
if (!wrap) return;
var panel = wrap.querySelector('.mdtFloatTocPanel');
if (!panel) return;
if (!isDesktop()) {
wrap.style.top = '';
wrap.style.right = '';
wrap.style.bottom = '';
panel.style.position = '';
panel.style.top = '';
panel.style.right = '';
panel.style.bottom = '';
panel.style.left = '';
panel.style.width = '';
panel.style.maxHeight = '';
return;
}
var topPx = getDockTopPx();
wrap.style.top = String(topPx) + 'px';
wrap.style.right = String(GAP_PX) + 'px';
wrap.style.bottom = 'auto';
// Fit into the right gutter: don't cover the white content card
var content = document.getElementById('mw-content') || document.getElementById('content');
if (!content || !content.getBoundingClientRect) return;
var rect = content.getBoundingClientRect();
var leftPx = Math.round(rect.right + GAP_PX);
var available = Math.round(window.innerWidth - leftPx - GAP_PX);
// No right gutter -> keep mobile popup style
if (available < 220) return;
panel.style.position = 'fixed';
panel.style.top = String(topPx) + 'px';
panel.style.right = String(GAP_PX) + 'px';
panel.style.bottom = 'auto';
panel.style.left = String(leftPx) + 'px';
panel.style.width = 'auto';
panel.style.maxHeight = 'calc(100vh - ' + String(topPx + GAP_PX) + 'px)';
// Default open once per page load
if (wrap.getAttribute('data-mdtDefaultOpen') !== '1') {
wrap.classList.add('mdtFloatTocOpen');
wrap.setAttribute('data-mdtDefaultOpen', '1');
}
}
function buildPanel(groups) {
injectCssOnce();
var wrap = document.createElement('div');
wrap.id = 'mdtFloatToc';
wrap.className = 'mdtFloatToc';
var openBtn = document.createElement('button');
openBtn.type = 'button';
openBtn.className = 'mdtFloatTocBtn';
openBtn.setAttribute('aria-label', '目录');
openBtn.textContent = '≡';
wrap.appendChild(openBtn);
var panel = document.createElement('div');
panel.className = 'mdtFloatTocPanel';
panel.setAttribute('role', 'dialog');
panel.setAttribute('aria-label', '目录');
wrap.appendChild(panel);
var head = document.createElement('div');
head.className = 'mdtFloatTocHead';
panel.appendChild(head);
var topBtn = document.createElement('button');
topBtn.type = 'button';
topBtn.className = 'mdtFloatTocTop';
topBtn.textContent = '↑ 返回顶部';
head.appendChild(topBtn);
var title = document.createElement('div');
title.className = 'mdtFloatTocTitle';
title.textContent = '目录';
head.appendChild(title);
var closeBtn = document.createElement('button');
closeBtn.type = 'button';
closeBtn.className = 'mdtFloatTocClose';
closeBtn.setAttribute('aria-label', '关闭');
closeBtn.textContent = 'X';
head.appendChild(closeBtn);
var ul = document.createElement('ul');
ul.className = 'mdtFloatTocList';
panel.appendChild(ul);
function openPanel(open) {
wrap.classList.toggle('mdtFloatTocOpen', open);
}
openBtn.addEventListener('click', function () {
openPanel(true);
applyDesktopDock(wrap);
});
closeBtn.addEventListener('click', function () {
openPanel(false);
});
topBtn.addEventListener('click', function () {
if (!isDesktop()) openPanel(false);
window.scrollTo({ top: 0, behavior: 'smooth' });
});
for (var i = 0; i < groups.length; i++) {
(function (g) {
var li = document.createElement('li');
li.className = 'mdtFloatTocItem mdtFloatTocGroup';
var row = document.createElement('div');
row.className = 'mdtFloatTocRow';
li.appendChild(row);
var a = document.createElement('a');
a.href = '#' + encodeURIComponent(g.id).replace(/%2F/g, '/');
a.textContent = g.text;
row.appendChild(a);
if (g.children && g.children.length) {
var toggle = document.createElement('button');
toggle.type = 'button';
toggle.className = 'mdtFloatTocGroupToggle';
toggle.setAttribute('aria-label', '展开/收起');
toggle.setAttribute('aria-expanded', 'false');
toggle.textContent = '>';
row.appendChild(toggle);
var sub = document.createElement('ul');
sub.className = 'mdtFloatTocSublist';
li.appendChild(sub);
for (var j = 0; j < g.children.length; j++) {
var c = g.children[j];
var cli = document.createElement('li');
cli.className = 'mdtFloatTocItem';
var ca = document.createElement('a');
ca.href = '#' + encodeURIComponent(c.id).replace(/%2F/g, '/');
ca.textContent = c.text;
cli.appendChild(ca);
sub.appendChild(cli);
}
toggle.addEventListener('click', function (ev) {
ev.preventDefault();
ev.stopPropagation();
var open = li.classList.toggle('mdtFloatTocGroupOpen');
toggle.setAttribute('aria-expanded', String(open));
toggle.textContent = open ? 'v' : '>';
});
}
ul.appendChild(li);
})(groups[i]);
}
// Click a toc item -> smooth scroll
wrap.addEventListener('click', function (ev) {
var target = ev.target;
if (!target) return;
var a = target.closest ? target.closest('a') : null;
if (!a) return;
var href = a.getAttribute('href') || '';
if (href.charAt(0) !== '#') return;
ev.preventDefault();
if (!isDesktop()) openPanel(false);
var id = decodeURIComponent(href.slice(1));
var el = document.getElementById(id);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
try {
history.replaceState(null, '', '#' + encodeURIComponent(id));
} catch (e) {}
}
});
// Mobile only: tap outside to close. Desktop: do nothing.
document.addEventListener('click', function (ev) {
if (isDesktop()) return;
if (!wrap.classList.contains('mdtFloatTocOpen')) return;
if (wrap.contains(ev.target)) return;
openPanel(false);
});
// Highlight active heading
var linkById = {};
var links = wrap.querySelectorAll('a');
for (var k = 0; k < links.length; k++) {
var id2 = decodeURIComponent((links[k].getAttribute('href') || '').slice(1));
linkById[id2] = links[k];
}
var ids = flattenIds(groups);
var ticking = false;
function updateActive() {
ticking = false;
var bestId = '';
var bestTop = -Infinity;
for (var i2 = 0; i2 < ids.length; i2++) {
var el2 = document.getElementById(ids[i2]);
if (!el2) continue;
var rect = el2.getBoundingClientRect();
if (rect.top <= 120 && rect.top > bestTop) {
bestTop = rect.top;
bestId = ids[i2];
}
}
for (var idKey in linkById) {
linkById[idKey].classList.toggle('mdtFloatTocActive', idKey === bestId);
}
}
window.addEventListener(
'scroll',
function () {
if (ticking) return;
ticking = true;
window.requestAnimationFrame(updateActive);
},
{ passive: true }
);
return wrap;
}
var resizeBound = false;
function initFloatToc($content) {
if (!isViewMode()) return;
if (document.getElementById('mdtFloatToc')) {
applyDesktopDock(document.getElementById('mdtFloatToc'));
return;
}
var content = $content && $content[0] ? $content[0] : null;
var root =
content || document.querySelector('.mw-parser-output') || document.getElementById('mw-content-text');
if (!root) return;
ensureHeadingIds(root);
var groups = collectGroups(root);
if (!groups.length) return;
var wrap = buildPanel(groups);
document.body.appendChild(wrap);
applyDesktopDock(wrap);
if (!resizeBound) {
resizeBound = true;
window.addEventListener(
'resize',
function () {
var el = document.getElementById('mdtFloatToc');
if (el) applyDesktopDock(el);
},
{ passive: true }
);
window.addEventListener('load', function () {
var el = document.getElementById('mdtFloatToc');
if (el) applyDesktopDock(el);
});
}
}
mw.loader.using(['mediawiki.util']).then(function () {
if (mw.hook && window.jQuery) {
mw.hook('wikipage.content').add(initFloatToc);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
initFloatToc(null);
});
} else {
initFloatToc(null);
}
});
})();
/* MDTWIKI_APPEND_ICON_TOOL v20260123
* Paste this file at the END of MediaWiki:Common.js (do not replace your existing code).
* Timeless skin only. Works in action=edit (source editor textarea wpTextbox1).
*/
(function () {
'use strict';
if (!window.mw) return;
if (window.__mdtIconEditorToolInit) return;
window.__mdtIconEditorToolInit = true;
mw.loader.using(['mediawiki.util'], function () {
var skin = String(mw.config.get('skin') || '').toLowerCase();
if (skin !== 'timeless') return;
var action = String(mw.config.get('wgAction') || 'view').toLowerCase();
if (action !== 'edit') return;
var MDT_ICON_SIZE = 18;
// Map: page title (wgPageName format) -> uploaded file name.
// Add more entries as needed.
var MDT_ICON_MAP = {
'铜': 'Item-copper-ui.png',
'钰': 'Item-lead-ui.png',
'煤炭': 'Item-coal-ui.png',
'石墨': 'Item-graphite-ui.png',
'钛': 'Item-titanium-ui.png',
'钱': 'Item-thorium-ui.png',
'硅': 'Item-silicon-ui.png',
'塑钢': 'Item-plastanium-ui.png',
'相织布': 'Item-phase-fabric-ui.png',
'巨浪合金': 'Item-surge-alloy-ui.png',
'孢子荐': 'Item-spore-pod-ui.png',
'沙': 'Item-sand-ui.png',
'爆炸混合物': 'Item-blast-compound-ui.png',
'硫化物': 'ohno.png',
'钢化玻璃': 'Item-metaglass-ui.png',
'废料': 'Item-scrap-ui.png',
'裂变产物': 'Item-fissile-matter-ui.png',
'钽': 'Item-beryllium-ui.png',
'钞': 'Item-tungsten-ui.png',
'氧化物': 'Item-oxide-ui.png',
'碳化物': 'Item-carbide-ui.png',
'休眠囊肿': 'Item-dormant-cyst-ui.png',
'水': 'Liquid-water-ui.png',
'矿渣': 'Liquid-slag-ui.png',
'石油': 'Liquid-oil-ui.png',
'冷冻液': 'Liquid-cryofluid-ui.png',
'瘤液': 'Liquid-neoplasm-ui.png',
'芳油': 'Liquid-arkycite-ui.png',
'鋠液': 'Liquid-gallium-ui.png',
'氧氧': 'Liquid-ozone-ui.png',
'氢气': 'Liquid-hydrogen-ui.png',
'氮气': 'Liquid-nitrogen-ui.png',
'氮气': 'Liquid-cyanogen-ui.png',
'尖刀': 'Unit-dagger-ui.png',
'战锤': 'Unit-mace-ui.png',
'堡垒': 'Unit-fortress-ui.png',
'新星': 'Unit-nova-ui.png',
'恒星': 'Unit-pulsar-ui.png',
'耀星': 'Unit-quasar-ui.png',
'爬虫': 'Unit-crawler-ui.png',
'毒螞': 'Unit-atrax-ui.png',
'血螲': 'Unit-spiroct-ui.png',
'毒蛇': 'Unit-arkyid-ui.png',
'天蝎': 'Unit-toxopid-ui.png',
'星辉': 'Unit-stell-ui.png',
'天垰': 'Unit-vela-ui.png',
'苍穹': 'Unit-corvus-ui.png',
'月影': 'Unit-antumbra-ui.png',
'日蚁': 'Unit-eclipse-ui.png',
'独影': 'Unit-obviate-ui.png',
'幻型': 'Unit-elude-ui.png',
'巨像': 'Unit-emanate-ui.png',
'雷雷': 'Unit-evoke-ui.png',
'要塞': 'Unit-conquer-ui.png',
'棒鱼': 'Unit-bryde-ui.png',
'飞鲨': 'Unit-minke-ui.png',
'战鲸': 'Unit-sei-ui.png',
'蛹龙': 'Unit-omura-ui.png',
'海神': 'Unit-retusa-ui.png',
'潜螺': 'Unit-cyerce-ui.png',
'电鳊': 'Unit-oxynoe-ui.png',
'江豚': 'Unit-risso-ui.png',
'玄武': 'Unit-navanax-ui.png',
'龙王': 'Unit-anthicus-ui.png',
'阿尔法': 'Unit-alpha-ui.png',
'贝塔': 'Unit-beta-ui.png',
'伽马': 'Unit-gamma-ui.png',
'权杖': 'Unit-scepter-ui.png',
'王座': 'Unit-reign-ui.png',
'灾星': 'Unit-scathe-ui.png',
'死星': 'Unit-horizon-ui.png',
'围护': 'Unit-avert-ui.png',
'徙迹': 'Unit-locus-ui.png',
'准绳': 'Unit-precept-ui.png',
'征服': 'Unit-vanquish-ui.png',
'领主': 'Unit-tecta-ui.png',
'天守': 'Unit-collaris-ui.png',
'天赐': 'Unit-disrupt-ui.png',
'天灾': 'Unit-quell-ui.png',
'天理': 'Unit-elude-ui.png',
'天帝': 'Unit-emanate-ui.png',
'拉脱': 'Unit-flare-ui.png',
'遮蔽': 'Unit-horizon-ui.png',
'消散': 'Unit-disperse-ui.png',
'遼止': 'Unit-obviate-ui.png',
'悲恱': 'Unit-merui-ui.png',
'苏醒': 'Unit-emanate-ui.png',
'策动': 'Unit-incite-ui.png',
'发散': 'Unit-disperse-ui.png',
'货运无人机': 'Unit-cargo-drone-ui.png',
'装配无人机': 'Unit-assembly-drone-ui.png',
'Latum': 'Unit-latum-ui.png',
'Renale': 'Unit-renale-ui.png',
'差扰': 'ohno.png',
'悬崖': 'Block-cliff-ui.png',
'砂岩': 'Block-dacite-ui.png',
'玄武岩石块': 'Block-basalt-boulder-ui.png',
'窑炉': 'Block-kiln-ui.png',
'石墨压缩机': 'Block-graphite-press-ui.png',
'多重压缩机': 'Block-multi-press-ui.png',
'敌人出生点': 'Block-spawn-ui.png',
'移除墙体': 'Block-remove-wall-ui.png',
'移除矿': 'Block-remove-ore-ui.png',
'初代核心': 'Block-core-shard-ui.png',
'次代核心': 'Block-core-foundation-ui.png',
'终代核心': 'Block-core-nucleus-ui.png',
'双管': 'Block-duo-ui.png',
'火焰': 'Block-scorch-ui.png',
'分裂': 'Block-ripple-ui.png',
'冰霍': 'Block-hail-ui.png',
'蓝瑞': 'Block-lancer-ui.png',
'传送带': 'Block-conveyor-ui.png',
'钛传送带': 'Block-titanium-conveyor-ui.png',
'塑钢传送带': 'Block-plastanium-conveyor-ui.png',
'装甲传送带': 'Block-armored-conveyor-ui.png',
'交叉器': 'Block-junction-ui.png',
'路由器': 'Block-router-ui.png',
'分配器': 'Block-distributor-ui.png',
'分类器': 'Block-sorter-ui.png',
'反向分类器': 'Block-inverted-sorter-ui.png',
'信息板': 'Block-message-ui.png',
'强化信息板': 'Block-reinforced-message-ui.png',
'世界信息板': 'Block-world-message-ui.png',
'世界开关': 'Block-world-switch-ui.png',
'照明器': 'Block-illuminator-ui.png',
'溢流门': 'Block-overflow-gate-ui.png',
'反向溢流门': 'Block-underflow-gate-ui.png',
'硅冶炼厂': 'Block-silicon-smelter-ui.png',
'相织布编织器': 'Block-phase-weaver-ui.png',
'粉碎机': 'Block-pulverizer-ui.png',
'冷冻液混合器': 'Block-cryofluid-mixer-ui.png',
'熔炉': 'Block-melter-ui.png',
'焚化炉': 'Block-incinerator-ui.png',
'孢子压缩机': 'Block-spore-press-ui.png',
'分离机': 'Block-separator-ui.png',
'煤炭离心机': 'Block-coal-centrifuge-ui.png',
'电力节点': 'Block-power-node-ui.png',
'大型电力节点': 'Block-power-node-large-ui.png',
'巨浪电力塔': 'Block-surge-tower-ui.png',
'二极管': 'Block-diode-ui.png',
'电池': 'Block-battery-ui.png',
'大型电池': 'Block-battery-large-ui.png',
'火力发电机': 'Block-combustion-generator-ui.png',
'涡轮发电机': 'Block-steam-generator-ui.png',
'温差发电机': 'Block-thermal-generator-ui.png',
'冲击反应堆': 'Block-impact-reactor-ui.png',
'机械钻头': 'Block-mechanical-drill-ui.png',
'气动钻头': 'Block-pneumatic-drill-ui.png',
'激光钻头': 'Block-laser-drill-ui.png',
'抽水机': 'Block-water-extractor-ui.png',
'培养机': 'Block-cultivator-ui.png',
'导管': 'Block-conduit-ui.png',
'机械泵': 'Block-mechanical-pump-ui.png',
'物品源': 'Block-item-source-ui.png',
'物品黑洞': 'Block-item-void-ui.png',
'液体源': 'Block-liquid-source-ui.png',
'液体黑洞': 'Block-liquid-void-ui.png',
'电力黑洞': 'Block-power-void-ui.png',
'电力源': 'Block-power-source-ui.png',
'装卸器': 'Block-unloader-ui.png',
'仓库': 'Block-vault-ui.png',
'波浪': 'Block-wave-ui.png',
'海嗔': 'Block-tsunami-ui.png',
'蜂群': 'Block-swarmer-ui.png',
'齐射': 'Block-salvo-ui.png',
'浪涌': 'Block-surge-ui.png',
'相织布传送带桥': 'Block-phase-conveyor-ui.png',
'传送带桥': 'Block-bridge-conveyor-ui.png',
'塑钢压缩机': 'Block-plastanium-compressor-ui.png',
'硫化物混合器': 'Block-sulfide-mixer-ui.png',
'爆炸物混合器': 'Block-blast-mixer-ui.png',
'太阳能板': 'Block-solar-panel-ui.png',
'大型太阳能板': 'Block-solar-panel-large-ui.png',
'石油钻井': 'Block-oil-extractor-ui.png',
'维修点': 'Block-repair-point-ui.png',
'维修塔': 'Block-repair-turret-ui.png',
'脉冲导管': 'Block-pulse-conduit-ui.png',
'电镀导管': 'Block-plated-conduit-ui.png',
'相织布导管桥': 'Block-phase-conduit-ui.png',
'流体路由器': 'Block-liquid-router-ui.png',
'流体储罐': 'Block-liquid-tank-ui.png',
'流体容器': 'Block-liquid-container-ui.png',
'流体交叉器': 'Block-liquid-junction-ui.png',
'导管桥': 'Block-bridge-conduit-ui.png',
'回转泵': 'Block-rotary-pump-ui.png',
'钱反应堆': 'Block-thorium-reactor-ui.png',
'质量驱动器': 'Block-mass-driver-ui.png',
'爆破钻头': 'Block-blast-drill-ui.png',
'脉冲泵': 'Block-impulse-pump-ui.png',
'热能发电机': 'Block-differential-generator-ui.png',
'合金冶炼厂': 'Block-alloy-smelter-ui.png',
'修理器': 'Block-mender-ui.png',
'修理投影': 'Block-mend-projector-ui.png',
'合金墙': 'Block-surge-wall-ui.png',
'大型合金墙': 'Block-surge-wall-large-ui.png',
'气旋': 'Block-cyclone-ui.png',
'雷光': 'Block-arc-ui.png',
'脉冲地雷': 'Block-shock-mine-ui.png',
'超速投影': 'Block-overdrive-projector-ui.png',
'力墙投影': 'Block-force-projector-ui.png',
'电弧': 'Block-arc-ui.png',
'RTG发电机': 'Block-rtg-generator-ui.png',
'幻影': 'Block-phantom-ui.png',
'熔毁': 'Block-meltdown-ui.png',
'厄兆': 'Block-afflict-ui.png',
'容器': 'Block-container-ui.png',
'发射台': 'Block-launch-pad-ui.png',
'接收台': 'Block-landing-pad-ui.png',
'裂解': 'Block-disassembler-ui.png',
'陆军工厂': 'Block-ground-factory-ui.png',
'空军工厂': 'Block-air-factory-ui.png',
'海军工厂': 'Block-naval-factory-ui.png',
'数增级单位重构工厂': 'Block-additive-reconstructor-ui.png',
'倍乘级单位重构工厂': 'Block-multiplicative-reconstructor-ui.png',
'多幂级单位重构工厂': 'Block-exponential-reconstructor-ui.png',
'无量级单位重构工厂': 'Block-tetrative-reconstructor-ui.png',
'载荷传送带': 'Block-payload-conveyor-ui.png',
'载荷路由器': 'Block-payload-router-ui.png',
'物品管道': 'Block-duct-ui.png',
'物品管道路由器': 'Block-duct-router-ui.png',
'物品管道桥': 'Block-duct-bridge-ui.png',
'大型载荹质量驱动器': 'Block-large-payload-mass-driver-ui.png',
'载荹黑洞': 'Block-payload-void-ui.png',
'载荹源': 'Block-payload-source-ui.png',
'解离机': 'Block-disassembler-ui.png',
'热能坙坙': 'Block-slag-heater-ui.png',
'超速窄顶': 'Block-overdrive-dome-ui.png',
'行星际加速器': 'Block-interplanetary-accelerator-ui.png',
'勋筑器': 'Block-constructor-ui.png',
'大型勋筑器': 'Block-large-constructor-ui.png',
'大型解构器': 'Block-deconstructor-ui.png',
'载荹装载器': 'Block-payload-loader-ui.png',
'载荹卸载器': 'Block-payload-unloader-ui.png',
'热量源': 'Block-heat-source-ui.png',
'空': 'Block-empty-ui.png',
'流纹岩坑': 'Block-rhyolite-crater-ui.png',
'粗糙流纹岩': 'Block-rough-rhyolite-ui.png',
'流纹岩': 'Block-rhyolite-ui.png',
'黄石': 'Block-yellow-stone-ui.png',
'碳石': 'Block-carbon-stone-ui.png',
'铁石': 'Block-ferric-stone-ui.png',
'铁际石坑': 'Block-ferric-craters-ui.png',
'钽石': 'Block-beryllic-stone-ui.png',
'晶石': 'Block-crystalline-stone-ui.png',
'晶石地板': 'Block-crystal-floor-ui.png',
'黄石地板': 'Block-yellow-stone-plates-ui.png',
'红石': 'Block-red-stone-ui.png',
'高密红石': 'Block-dense-red-stone-ui.png',
'红冰': 'Block-red-ice-ui.png',
//'芳油': 'Block-arkyic-stone-ui.png', 这是地板!ai都不看重复的吗
'芳石': 'Block-arkyic-stone-ui.png',
'流纹石喷口': 'Block-rhyolite-vent-ui.png',
'碳石喷口': 'Block-carbon-vent-ui.png',
'芳石喷口': 'Block-arkyic-vent-ui.png',
'黄石喷口': 'Block-yellow-stone-vent-ui.png',
'红石喷口': 'Block-red-stone-vent-ui.png',
'晶石喷口': 'Block-crystalline-vent-ui.png',
'岩石喷口': 'Block-stone-vent-ui.png',
'玄武岩喷口': 'Block-basalt-vent-ui.png',
'红地垫': 'Block-redmat-ui.png',
'蓝地垫': 'Block-bluemat-ui.png',
'核心区': 'Block-core-zone-ui.png',
'风化墙': 'Block-regolith-wall-ui.png',
'黄石墙': 'Block-yellow-stone-wall-ui.png',
'流纹岩墙': 'Block-rhyolite-wall-ui.png',
'碳石墙': 'Block-carbon-wall-ui.png',
'铁石墙': 'Block-ferric-stone-wall-ui.png',
'钽石墙': 'Block-beryllic-stone-wall-ui.png',
'芳石墙': 'Block-arkyic-wall-ui.png',
'晶石墙': 'Block-crystalline-stone-wall-ui.png',
'红冰墙': 'Block-red-ice-wall-ui.png',
'红石墙': 'Block-red-stone-wall-ui.png',
'红钻墙': 'Block-red-diamond-wall-ui.png',
'赤藻': 'Block-redweed-ui.png',
'紫灌木丛': 'Block-pur-bush-ui.png',
'黄珊瑚': 'Block-yellowcoral-ui.png',
'碳石块': 'Block-carbon-boulder-ui.png',
'铁石块': 'Block-ferric-boulder-ui.png',
'钽石块': 'Block-beryllic-boulder-ui.png',
'黄石块': 'Block-yellow-stone-boulder-ui.png',
'芳石块': 'Block-arkyic-boulder-ui.png',
'水晶簇': 'Block-crystal-cluster-ui.png',
'鲜艳水晶簇': 'Block-vibrant-crystal-cluster-ui.png',
'风化晶体': 'Block-weathered-crystal-ui.png',
'晶石球': 'Block-crystal-orbs-ui.png',
'晶石块': 'Block-crystal-blocks-ui.png',
'红冰石块': 'Block-red-ice-boulder-ui.png',
'流纹石块': 'Block-rhyolite-boulder-ui.png',
'红石块': 'Block-red-stone-boulder-ui.png',
'石墨墙': 'Block-graphitic-wall-ui.png',
'电弧硅炉': 'Block-silicon-arc-furnace-ui.png',
'电解机': 'Block-electrolyzer-ui.png',
'大气收集器': 'Block-atmospheric-concentrator-ui.png',
'氧化室': 'Block-oxidation-chamber-ui.png',
'电制热机': 'Block-electric-heater-ui.png',
'矿渣制热机': 'Block-slag-heater-ui.png',
'相织制热机': 'Block-phase-heater-ui.png',
'热量传输机': 'Block-heat-redirector-ui.png',
'小型热量传输机': 'Block-small-heat-redirector-ui.png',
'热量路由器': 'Block-heat-router-ui.png',
'矿渣焚化炉': 'Block-slag-incinerator-ui.png',
'碳化物坙坙': 'Block-carbide-crucible-ui.png',
'矿渣离心机': 'Block-slag-centrifuge-ui.png',
'合金坙坙': 'Block-alloy-crucible-ui.png',
'氧合成机': 'Block-cyanogen-synthesizer-ui.png',
'相织布合成机': 'Block-phase-synthesizer-ui.png',
'热量反应堆': 'Block-heat-reactor-ui.png',
'钽墙': 'Block-beryllium-wall-ui.png',
'大型钽墙': 'Block-beryllium-wall-large-ui.png',
'钞墙': 'Block-tungsten-wall-ui.png',
'大型钞墙': 'Block-tungsten-wall-large-ui.png',
'防爆闸门': 'Block-blast-door-ui.png',
'碳化物墙': 'Block-carbide-wall-ui.png',
'大型碳化物墙': 'Block-carbide-wall-large-ui.png',
'强化合金墙': 'Block-reinforced-surge-wall-ui.png',
'大型强化合金墙': 'Block-reinforced-surge-wall-large-ui.png',
'盾墙': 'Block-shielded-wall-ui.png',
'雷达': 'Block-radar-ui.png',
'建造塔': 'Block-build-tower-ui.png',
'再生投影器': 'Block-regen-projector-ui.png',
'震爆塔': 'Block-shockwave-tower-ui.png',
'护盾投影器': 'Block-shield-projector-ui.png',
'大型护盾投影器': 'Block-large-shield-projector-ui.png',
'装甲管道': 'Block-armored-duct-ui.png',
'溢流管道': 'Block-overflow-duct-ui.png',
'反向溢流管': 'Block-underflow-duct-ui.png',
'管道装卸器': 'Block-duct-unloader-ui.png',
'合金传送带': 'Block-surge-conveyor-ui.png',
'合金路由器': 'Block-surge-router-ui.png',
'单位物流装载器': 'Block-unit-cargo-loader-ui.png',
'单位物流卸载点': 'Block-unit-cargo-unload-point-ui.png',
'强化泵': 'Block-reinforced-pump-ui.png',
'强化导管': 'Block-reinforced-conduit-ui.png',
'强化流体交叉器': 'Block-reinforced-liquid-junction-ui.png',
'强化流体带桥': 'Block-reinforced-bridge-conduit-ui.png',
'强化流体路由器': 'Block-reinforced-liquid-router-ui.png',
'强化流体容器': 'Block-reinforced-liquid-container-ui.png',
'强化流体储罐': 'Block-reinforced-liquid-tank-ui.png',
'激光节点': 'Block-beam-node-ui.png',
'激光塔': 'Block-beam-tower-ui.png',
'激光连接器': 'Block-beam-link-ui.png',
'涡轮冷凝器': 'Block-turbine-condenser-ui.png',
'化学燃烧室': 'Block-chemical-combustion-chamber-ui.png',
'热解发生器': 'Block-pyrolysis-generator-ui.png',
'排气冷凝器': 'Block-vent-condenser-ui.png',
'墙壁粉碎机': 'Block-cliff-crusher-ui.png',
'高级墙壁粉碎机': 'Block-large-cliff-crusher-ui.png',
'等离子钻机': 'Block-plasma-bore-ui.png',
'大型等离子钻机': 'Block-large-plasma-bore-ui.png',
'冲击钻头': 'Block-impact-drill-ui.png',
'爆裂钻头': 'Block-eruption-drill-ui.png',
'城堡核心': 'Block-core-citadel-ui.png',
'堡垒核心': 'Block-core-bastion-ui.png',
'卫城核心': 'Block-core-acropolis-ui.png',
'强化容器': 'Block-reinforced-container-ui.png',
'强化仓库': 'Block-reinforced-vault-ui.png',
'撕裂': 'Block-ripper-ui.png',
'升华': 'Block-sublimate-ui.png',
'泰坦': 'Block-titan-ui.png',
'驱离': 'Block-disperse-ui.png',
'劫难': 'Block-afflict-ui.png',
'光辉': 'Block-lustre-ui.png',
'创伤': 'Block-scathe-ui.png',
'坦克重构厂': 'Block-tank-refabricator-ui.png',
'机甲重构厂': 'Block-mech-refabricator-ui.png',
'飞船重构厂': 'Block-ship-refabricator-ui.png',
'坦克组装厂': 'Block-tank-assembler-ui.png',
'飞船组装厂': 'Block-ship-assembler-ui.png',
'机甲组装厂': 'Block-mech-assembler-ui.png',
'强化载荹传送带': 'Block-reinforced-payload-conveyor-ui.png',
'强化载荹路由器': 'Block-reinforced-payload-router-ui.png',
'载荹质量驱动器': 'Block-payload-mass-driver-ui.png',
'解构器': 'Block-deconstructor-ui.png',
'画板': 'Block-canvas-ui.png',
'世界处理器': 'Block-world-processor-ui.png',
'世界内存元': 'Block-world-cell-ui.png',
'坦克制造厂': 'Block-tank-fabricator-ui.png',
'机甲制造厂': 'Block-mech-fabricator-ui.png',
'飞船制造厂': 'Block-ship-fabricator-ui.png',
'高级再重构工厂': 'Block-prime-refabricator-ui.png',
'单位维修塔': 'Block-unit-repair-tower-ui.png',
'扩散': 'Block-diffuse-ui.png',
'基本装配厂模块': 'Block-basic-assembler-module-ui.png',
'天谦': 'Block-smite-ui.png',
'魔灵': 'Block-malign-ui.png',
'通量反应堆': 'Block-flux-reactor-ui.png',
'瘤变反应堆': 'Block-neoplasia-reactor-ui.png',
'开关': 'Block-switch-ui.png',
'微型处理器': 'Block-micro-processor-ui.png',
'逻辑处理器': 'Block-logic-processor-ui.png',
'超核处理器': 'Block-hyper-processor-ui.png',
'逻辑显示屏': 'Block-logic-display-ui.png',
'大型逻辑显示屏': 'Block-large-logic-display-ui.png',
'逻辑显示单元': 'Block-tile-logic-display-ui.png',
'内存元': 'Block-memory-cell-ui.png',
'内存库': 'Block-memory-bank-ui.png',
'草地': 'Block-grass-ui.png',
'矿渣液': 'Block-molten-slag-ui.png',
//'冷冻液': 'Block-pooled-cryofluid-ui.png', 这是地板!ai都不看重复的吗
'太空': 'Block-space-ui.png',
'盐碱地': 'Block-salt-ui.png',
'盐墙': 'Block-salt-wall-ui.png',
'鹏卵石': 'Block-pebbles-ui.png',
'卷须': 'Block-tendrils-ui.png',
'沙墙': 'Block-sand-wall-ui.png',
'孢子树': 'Block-spore-pine-ui.png',
'孢子墙': 'Block-spore-wall-ui.png',
'石块': 'Block-stone-ui.png',
'雪石块': 'Block-snow-boulder-ui.png',
'雪树': 'Block-snow-pine-ui.png',
'页岩地': 'Block-shale-ui.png',
'页岩石块': 'Block-shale-boulder-ui.png',
'芜藻地': 'Block-moss-ui.png',
'灌木丛': 'Block-shrubs-ui.png',
'孢子芜藻地': 'Block-spore-moss-ui.png',
'页岩墙': 'Block-shale-wall-ui.png',
'废墙': 'Block-scrap-wall-ui.png',
'大型废墙': 'Block-scrap-wall-large-ui.png',
'巨型废墙': 'Block-scrap-wall-huge-ui.png',
'超巨型废墙': 'Block-scrap-wall-gigantic-ui.png',
'推进器残骵': 'Block-thruster-ui.png',
'深水': 'Block-deep-water-ui.png',
//'水': 'Block-shallow-water-ui.png', 这是地板!ai都不看重复的吗?
'污水': 'Block-tainted-water-ui.png',
'深污水': 'Block-deep-tainted-water-ui.png',
'黑沙污水': 'Block-darksand-tainted-water-ui.png',
'石油': 'Block-tar-ui.png',
'石头': 'Block-stone-ui.png',
'沙子': 'Block-sand-floor-ui.png',
'黑沙': 'Block-darksand-ui.png',
'冰': 'Block-ice-ui.png',
'雪': 'Block-snow-ui.png',
'陶石坑': 'Block-crater.png',
'浅滩': 'Block-shallow-water-ui.png',
'黑沙浅滩': 'Block-darksand-water-ui.png',
'焦土': 'Block-scorch-ui.png',
'安山岩': 'Block-dacite-ui.png',
'流纹岩': 'Block-rhyolite-ui.png',
'安山岩墙': 'Block-dacite-wall-ui.png',
'安山石块': 'Block-dacite-boulder-ui.png',
'冰雪地': 'Block-ice-snow-ui.png',
'石墙': 'Block-stone-wall-ui.png',
'冰墙': 'Block-ice-wall-ui.png',
'雪墙': 'Block-snow-wall-ui.png',
'沙丘岩': 'Block-dune-wall-ui.png',
'松树': 'Block-pine-ui.png',
'泥土': 'Block-dirt-ui.png',
'泥土墙': 'Block-dirt-wall-ui.png',
'泥巴': 'Block-mud-ui.png',
'枯萎的白树': 'Block-white-tree-dead-ui.png',
'白树': 'Block-white-tree-ui.png',
'孢子簇': 'Block-spore-cluster-ui.png',
'金属地板1': 'Block-metal-floor-ui.png',
'金属地板2': 'Block-metal-floor-2-ui.png',
'金属地板3': 'Block-metal-floor-3-ui.png',
'金属地板4': 'Block-metal-floor-4-ui.png',
'金属地板5': 'Block-metal-floor-5-ui.png',
'损坏的金属地板': 'Block-metal-floor-damaged-ui.png',
'金属地基1': 'Block-metal-tiles-1-ui.png',
'金属地基2': 'Block-metal-tiles-2-ui.png',
'金属地基3': 'Block-metal-tiles-3-ui.png',
'金属地基4': 'Block-metal-tiles-4-ui.png',
'金属地基5': 'Block-metal-tiles-5-ui.png',
'金属地基6': 'Block-metal-tiles-6-ui.png',
'金属地基7': 'Block-metal-tiles-7-ui.png',
'金属地基8': 'Block-metal-tiles-8-ui.png',
'金属地基9': 'Block-metal-tiles-9-ui.png',
'金属地基10': 'Block-metal-tiles-10-ui.png',
'金属地基11': 'Block-metal-tiles-11-ui.png',
'金属地基12': 'Block-metal-tiles-12-ui.png',
'金属地基13': 'Block-metal-tiles-13-ui.png',
'金属墙1': 'Block-metal-wall-1-ui.png',
'金属墙2': 'Block-metal-wall-2-ui.png',
'金属墙3': 'Block-metal-wall-3-ui.png',
'染色地板': 'Block-colored-floor-ui.png',
'染色墙壈': 'Block-colored-wall-ui.png',
'标识贴片': 'Block-character-overlay-ui.png',
'标识贴片(白色)': 'Block-character-overlay-white-ui.png',
'符文贴片': 'Block-rune-overlay-ui.png',
'符文贴片(红队)': 'Block-rune-overlay-crux-ui.png',
'暗面板1': 'Block-dark-panel-1-ui.png',
'暗面板2': 'Block-dark-panel-2-ui.png',
'暗面板3': 'Block-dark-panel-3-ui.png',
'暗面板4': 'Block-dark-panel-4-ui.png',
'暗面板5': 'Block-dark-panel-5-ui.png',
'暗面板6': 'Block-dark-panel-6-ui.png',
'暗金属': 'Block-dark-metal-ui.png',
'玄武岩': 'Block-basalt-ui.png',
'灼热岩石': 'Block-hotrock-ui.png',
'熔融岩石': 'Block-magmarock-ui.png',
'铜墙': 'Block-copper-wall-ui.png',
'大型铜墙': 'Block-copper-wall-large-ui.png',
'钛墙': 'Block-titanium-wall-ui.png',
'大型钛墙': 'Block-titanium-wall-large-ui.png',
'塑钢墙': 'Block-plastanium-wall-ui.png',
'大型塑钢墙': 'Block-plastanium-wall-large-ui.png',
'相织布墙': 'Block-phase-wall-ui.png',
'大型相织布墙': 'Block-phase-wall-large-ui.png',
'钱墙': 'Block-thorium-wall-ui.png',
'大型钱墙': 'Block-thorium-wall-large-ui.png',
'门': 'Block-door-ui.png',
'大门': 'Block-door-large-ui.png',
'塞普罗': 'Planet-serpulo.png',
'埃里克尔': 'Planet-erekir.png',
'太阳': 'Sun.png',
'降雨': 'ohno.png',
'降雪': 'ohno.png',
'沙尘暴': 'ohno.png',
'孢子风暴': 'ohno.png',
'雾': 'ohno.png',
'燃烧': 'Status-burning-ui.png',
'冻结': 'Status-freezing-ui.png',
'潮湿': 'Status-wet-ui.png',
'泥污': 'Status-muddy-ui.png',
'熔化': 'Status-melting-ui.png',
'弱化': 'Status-slow-ui.png',
'麻痹': 'Status-electrified-ui.png',
'孢子减速': 'Status-spore-slowed-ui.png',
'油浸': 'Status-tarred-ui.png',
'过载': 'Status-overdrive-ui.png',
'超频': 'Status-overclock-ui.png',
'电击': 'Status-shocked-ui.png',
'爆炸': 'Status-blasted-ui.png',
'腐蚀': 'Status-corroded-ui.png',
'静止': 'Status-unmoving-ui.png',
'Boss': 'Status-boss-ui.png'
};
function getEditorTextarea() {
return document.getElementById('wpTextbox1') ||
document.querySelector('textarea#wpTextbox1');
}
function buildIconWikitext(filename, title) {
var file = String(filename);
var t = String(title);
return '<span class="mdtPixelIcon">[[File:' + file + '|' + String(MDT_ICON_SIZE) + 'px|link=' + t + ']]</span>';
}
function buildTitlePattern(titles) {
// Prefer longer first to avoid partial matches.
var list = titles.slice().sort(function (a, b) { return b.length - a.length; });
var escaped = [];
for (var i = 0; i < list.length; i++) {
escaped.push(list[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
}
return escaped.join('|');
}
function convertWikitext(text) {
var titles = Object.keys(MDT_ICON_MAP || {});
if (!titles.length) return { text: text, changed: 0 };
var pattern = buildTitlePattern(titles);
// Only convert links like [[Title]] or [[Title|Label]].
// Skip links already preceded by mdtPixelIcon span.
var re = new RegExp('\\[\\[(' + pattern + ')(?:\\|[^\\]]*)?\\]\\]', 'g');
var changed = 0;
var out = text.replace(re, function (m, title, offset) {
var before = text.slice(Math.max(0, offset - 120), offset);
if (before.indexOf('class="mdtPixelIcon"') !== -1) return m;
if (/\[\[File:|\[\[Image:/i.test(m)) return m;
var filename = MDT_ICON_MAP[title];
if (!filename) return m;
changed++;
return buildIconWikitext(filename, title) + ' ' + m;
});
return { text: out, changed: changed };
}
function initEditorTool() {
var ta = getEditorTextarea();
if (!ta) return;
if (ta.getAttribute('data-mdtIconTool') === '1') return;
ta.setAttribute('data-mdtIconTool', '1');
var host = document.createElement('div');
host.style.margin = '0 0 8px 0';
host.style.display = 'flex';
host.style.gap = '8px';
host.style.flexWrap = 'wrap';
host.style.alignItems = 'center';
var btn = document.createElement('button');
btn.type = 'button';
btn.className = 'mw-ui-button mw-ui-progressive';
btn.textContent = '一键配图标';
var undo = document.createElement('button');
undo.type = 'button';
undo.className = 'mw-ui-button';
undo.textContent = '撤销配图标';
undo.disabled = true;
var note = document.createElement('span');
note.style.opacity = '0.75';
note.style.fontSize = '12px';
note.textContent = '只处理[[...]]链接';
host.appendChild(btn);
host.appendChild(undo);
host.appendChild(note);
if (ta.parentNode) ta.parentNode.insertBefore(host, ta);
var backup = '';
btn.addEventListener('click', function () {
var current = String(ta.value || '');
var result = convertWikitext(current);
if (!result.changed) {
alert('没有可替换的链接');
return;
}
backup = current;
undo.disabled = false;
ta.value = result.text;
alert('已插入 ' + String(result.changed) + ' 个图标');
});
undo.addEventListener('click', function () {
if (!backup) {
alert('没有备份');
return;
}
ta.value = backup;
backup = '';
undo.disabled = true;
alert('已撤销');
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initEditorTool);
} else {
initEditorTool();
}
});
})();
/* Mindustry 地图库小部件(MediaWiki)
*/
(() => {
"use strict";
const DEFAULT_CONFIG = {
apiBase: "https://api.mindustry.top/",
pageSize: 15,
containerSelector: ".mindustry-map-widget",
enableInfiniteScroll: true,
onlyOnPageNames: ["地图库"],
showSort: true,
maxTagOptions: 48,
detailTemplate: "https://www.mindustry.top/map/{id}/latest",
tagOptions: null,
};
const userConfig =
(typeof window !== "undefined" && window.MindustryMapWidgetConfig) || {};
const config = { ...DEFAULT_CONFIG, ...userConfig };
const sorters = [
{ value: "", label: "热度" },
{ value: "updateTime", label: "更新时间" },
{ value: "createTime", label: "发布时间" },
{ value: "download", label: "下载量" },
{ value: "rating", label: "评分" },
{ value: "like", label: "点赞数" },
];
const normalizeApiBase = (base) => (base.endsWith("/") ? base : base + "/");
config.apiBase = normalizeApiBase(String(config.apiBase || ""));
function mapUrl(raw) {
const s = String(raw || "");
if (s.startsWith("/api/")) return config.apiBase + s.substring(5);
return s;
}
function resolveTemplate(template, vars) {
let s = String(template || "");
for (const [k, v] of Object.entries(vars || {})) {
s = s.replaceAll(`{${k}}`, String(v));
}
return s;
}
function el(tag, attrs, ...children) {
const node = document.createElement(tag);
if (attrs) {
for (const [k, v] of Object.entries(attrs)) {
if (v === undefined || v === null) continue;
if (k === "class") node.className = String(v);
else if (k === "text") node.textContent = String(v);
else if (k === "html") node.innerHTML = String(v);
else if (k.startsWith("on") && typeof v === "function")
node.addEventListener(k.substring(2), v);
else node.setAttribute(k, String(v));
}
}
for (const child of children.flat()) {
if (child === undefined || child === null) continue;
node.append(child instanceof Node ? child : document.createTextNode(String(child)));
}
return node;
}
function safeOpen(url) {
window.open(url, "_blank", "noopener,noreferrer");
}
function isFiveDigits(s) {
return /^\d{5}$/.test(String(s || "").trim());
}
function buildSearchString(keyword, selectedTags, sort) {
let s = String(keyword || "").replace(/\s+/g, " ").trim();
for (const t of Array.isArray(selectedTags) ? selectedTags : []) {
const tt = String(t || "").trim();
if (!tt) continue;
s += ` ${tt} `;
}
if (sort) s += ` @sort:${sort} `;
return s.replace(/\s+/g, " ").trim();
}
function mapsListUrl(begin, search) {
const url = new URL(config.apiBase + "maps/list");
url.searchParams.set("begin", String(begin || 0));
url.searchParams.set("search", String(search || ""));
return url.toString();
}
function detailUrl(thread) {
if (typeof config.detailUrl === "function") return config.detailUrl(thread);
const id = encodeURIComponent(String(thread));
return resolveTemplate(config.detailTemplate, { id });
}
function downloadUrl(thread) {
return mapUrl(`/api/maps/${encodeURIComponent(String(thread))}.msav`);
}
function setActiveButton(groupEl, value) {
if (!groupEl) return;
for (const btn of groupEl.querySelectorAll("button[data-value]")) {
btn.classList.toggle(
"is-active",
btn.getAttribute("data-value") === String(value || ""),
);
}
}
function parseTag(raw) {
const parts = String(raw || "").split("搂");
const text = (parts[0] || "").trim();
const color = (parts[1] || "").trim();
return { text, color };
}
function normalizeTagOptions(raw) {
const out = [];
if (!raw) return out;
const arr = Array.isArray(raw) ? raw : [raw];
for (const item of arr) {
if (typeof item === "string") {
const text = item.trim();
if (text) out.push({ text, color: "" });
continue;
}
if (!item || typeof item !== "object") continue;
const text = String(item.text ?? item.label ?? "").trim();
if (!text) continue;
const color = String(item.color ?? "").trim();
out.push({ text, color });
}
return out;
}
function normalizePageNameList(raw) {
if (raw === null) return null;
if (raw === undefined) return null;
if (raw === false) return null;
const arr = Array.isArray(raw) ? raw : [raw];
const list = arr
.map((it) => String(it || "").trim())
.filter((it) => it.length > 0);
return list.length > 0 ? list : null;
}
function shouldInitOnThisPage() {
const only = normalizePageNameList(config.onlyOnPageNames);
if (!only) return true;
if (!window.mw || !window.mw.config || typeof window.mw.config.get !== "function") {
return true;
}
const pageName = window.mw.config.get("wgPageName");
if (!pageName) return true;
return only.includes(String(pageName));
}
function renderWidget(root) {
const state = {
keyword: "",
sort: "",
selectedTags: [],
begin: 0,
hasNext: true,
loading: false,
abort: null,
pagesLoaded: 0,
tagStats: new Map(),
};
const searchInput = el("input", {
type: "search",
placeholder: "查找地图名称(输入 5 位地图ID 可直接打开详情)",
value: "",
});
const searchBtn = el("button", { class: "mmw-btn mmw-btn-primary", type: "button", text: "搜索" });
const clearBtn = el("button", { class: "mmw-btn", type: "button", text: "清空" });
const searchRow = el("div", { class: "mmw-search mmw-search-row" }, searchInput, searchBtn, clearBtn);
const tagPickerGroup = el("div", { class: "mmw-tag-picker", "data-group": "tags" });
const clearTagsBtn = el("button", {
class: "mmw-tag mmw-tag-btn mmw-tag-clear",
type: "button",
text: "清除标签",
title: "清除已选择的标签",
});
const tagRow = el(
"div",
{ class: "mmw-filter mmw-filter-tags" },
el("span", { class: "mmw-filter-label", text: "标签筛选:" }),
tagPickerGroup,
clearTagsBtn,
);
const sortGroup = el(
"div",
{ class: "mmw-btn-group", "data-group": "sort" },
...sorters.map((s) =>
el("button", { class: "mmw-btn", type: "button", "data-value": s.value, text: s.label }),
),
);
const sortRow = el(
"div",
{ class: "mmw-filter" },
el("span", { class: "mmw-filter-label", text: "排序方式:" }),
sortGroup,
);
const filters = el(
"div",
{ class: "mmw-filters" },
tagRow,
config.showSort ? sortRow : null,
);
const grid = el("div", { class: "mmw-grid" });
const empty = el("div", { class: "mmw-muted", text: "暂无数据(尝试切换筛选或关键词)" });
const status = el("div", { class: "mmw-muted", text: "" });
const loadMoreBtn = el("button", { class: "mmw-btn", type: "button", text: "加载更多" });
const footer = el("div", { class: "mmw-footer" }, loadMoreBtn, status);
const sentinel = el("div", { style: "height: 1px;" });
function setStatus(text) {
status.textContent = String(text || "");
}
function setLoading(loading) {
state.loading = !!loading;
loadMoreBtn.disabled = state.loading;
searchBtn.disabled = state.loading;
clearBtn.disabled = state.loading;
clearTagsBtn.disabled = state.loading;
setStatus(state.loading ? "加载中…" : "");
}
function clearGrid() {
grid.textContent = "";
grid.append(empty);
}
function mapTagTexts(map) {
const rawTags = Array.isArray(map?.tags) ? map.tags : [];
const texts = [];
for (const raw of rawTags) {
const { text } = parseTag(raw);
if (text) texts.push(text);
}
return texts;
}
function updateTagStatsFromMaps(maps) {
for (const map of Array.isArray(maps) ? maps : []) {
for (const raw of Array.isArray(map?.tags) ? map.tags : []) {
const { text, color } = parseTag(raw);
if (!text) continue;
const prev = state.tagStats.get(text);
if (!prev) state.tagStats.set(text, { count: 1, color: color || "" });
else state.tagStats.set(text, { count: prev.count + 1, color: prev.color || color || "" });
}
}
}
function isTagSelected(tag) {
return state.selectedTags.includes(String(tag));
}
function toggleTag(tag) {
const t = String(tag || "").trim();
if (!t) return;
if (isTagSelected(t)) state.selectedTags = state.selectedTags.filter((x) => x !== t);
else state.selectedTags = [...state.selectedTags, t];
renderTagPicker();
void load(true);
}
function clearTags() {
if (state.selectedTags.length === 0) return;
state.selectedTags = [];
renderTagPicker();
void load(true);
}
function renderTagPicker() {
tagPickerGroup.textContent = "";
const selected = state.selectedTags.slice();
const pinned = normalizeTagOptions(config.tagOptions).filter((it) => !selected.includes(it.text));
const entries = [...state.tagStats.entries()];
entries.sort((a, b) => {
const ac = a[1]?.count ?? 0;
const bc = b[1]?.count ?? 0;
if (bc !== ac) return bc - ac;
return a[0].localeCompare(b[0], "zh-Hans-CN-u-co-pinyin");
});
const max = Math.max(0, Number(config.maxTagOptions || 0));
const candidates = entries
.map(([text, meta]) => ({ text, color: meta?.color || "" }))
.filter((it) => !selected.includes(it.text) && !pinned.some((p) => p.text === it.text))
.slice(0, max);
const renderOne = ({ text, color }) => {
const btn = el("button", {
class: `mmw-tag mmw-tag-btn${isTagSelected(text) ? " is-active" : ""}`,
type: "button",
text,
"data-tag": text,
});
if (color) {
btn.style.borderColor = color;
btn.style.color = color;
btn.style.background = "transparent";
}
btn.addEventListener("click", () => toggleTag(text));
tagPickerGroup.append(btn);
};
for (const t of selected) renderOne({ text: t, color: state.tagStats.get(t)?.color || "" });
for (const it of pinned) renderOne(it);
for (const it of candidates) renderOne(it);
clearTagsBtn.style.display = state.selectedTags.length > 0 ? "" : "none";
}
function renderCard(map) {
const previewSrc = mapUrl(map.preview);
const card = el("div", { class: "mmw-card" });
const previewLink = el("a", {
class: "mmw-preview",
href: detailUrl(map.id),
target: "_blank",
rel: "noopener noreferrer",
title: "打开详情",
});
previewLink.append(el("img", { src: previewSrc, alt: "preview", loading: "lazy" }));
const tagsEl = el("div", { class: "mmw-tags" });
for (const rawTag of Array.isArray(map.tags) ? map.tags : []) {
const { text, color } = parseTag(rawTag);
if (!text) continue;
const tagEl = el("span", { class: "mmw-tag", text });
if (color) {
tagEl.style.borderColor = color;
tagEl.style.color = color;
tagEl.style.background = "transparent";
}
tagsEl.append(tagEl);
}
const nameEl = el("div", { class: "mmw-name", text: String(map.name || "") });
const descEl = el("div", { class: "mmw-desc", text: String(map.desc || "") });
const copyBtn = el("button", { type: "button", text: "复制ID" });
copyBtn.addEventListener("click", async () => {
const id = String(map.id ?? "");
try {
await navigator.clipboard.writeText(id);
setStatus(`已复制:${id}`);
setTimeout(() => setStatus(""), 1200);
} catch {
window.prompt("复制失败,请手动复制:", id);
}
});
const dlLink = el("a", {
href: downloadUrl(map.id),
target: "_blank",
rel: "noopener noreferrer",
text: "下载",
title: "下载 .msav",
});
const detailLink = el("a", {
href: detailUrl(map.id),
target: "_blank",
rel: "noopener noreferrer",
text: "详情",
title: "打开详情",
});
const actions = el("div", { class: "mmw-actions" }, copyBtn, dlLink, detailLink);
const body = el("div", { class: "mmw-body" }, tagsEl, nameEl, descEl, actions);
card.append(previewLink, body);
return card;
}
async function fetchPage(begin) {
if (state.abort) state.abort.abort();
state.abort = new AbortController();
const search = buildSearchString(state.keyword, state.selectedTags, state.sort);
const url = mapsListUrl(begin, search);
const res = await fetch(url, { signal: state.abort.signal, credentials: "omit" });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
if (!Array.isArray(data)) return [];
for (const it of data) {
if (it && typeof it === "object" && "preview" in it) it.preview = mapUrl(it.preview);
}
return data;
}
async function load(reset) {
if (state.loading) return;
if (reset) {
state.begin = 0;
state.hasNext = true;
state.pagesLoaded = 0;
clearGrid();
}
if (!state.hasNext) return;
setLoading(true);
try {
const page = await fetchPage(state.begin);
updateTagStatsFromMaps(page);
renderTagPicker();
state.pagesLoaded += 1;
state.begin += page.length;
state.hasNext = page.length >= Number(config.pageSize || 15);
if (state.begin === page.length) grid.textContent = "";
const selected = state.selectedTags.slice();
const filtered = selected.length === 0
? page
: page.filter((m) => {
const texts = mapTagTexts(m);
return selected.every((t) => texts.includes(t));
});
for (const map of filtered) grid.append(renderCard(map));
if (grid.childElementCount === 0) grid.append(empty);
loadMoreBtn.style.display = state.hasNext ? "" : "none";
setStatus(state.hasNext ? "" : "没有更多了");
} catch (e) {
const msg = (e && e.message) || String(e);
const lower = String(msg || "").toLowerCase();
const maybeCors =
lower.includes("failed to fetch") ||
lower.includes("networkerror") ||
lower.includes("load failed") ||
lower.includes("cors");
setStatus(
maybeCors
? "加载失败:无法请求接口(可能是跨域 CORS),请检查 apiBase 是否允许当前 Wiki 域名访问"
: `加载失败:${msg}`,
);
} finally {
setLoading(false);
}
}
function applyFiltersUI() {
setActiveButton(sortGroup, state.sort);
}
function commitSearch() {
const key = String(searchInput.value || "").replace(/\s+/g, " ").trim();
if (!key) {
state.keyword = "";
void load(true);
return;
}
if (isFiveDigits(key)) {
safeOpen(detailUrl(key));
return;
}
state.keyword = key;
void load(true);
}
sortGroup.addEventListener("click", (ev) => {
const btn = ev.target && ev.target.closest && ev.target.closest("button[data-value]");
if (!btn) return;
state.sort = btn.getAttribute("data-value") || "";
applyFiltersUI();
void load(true);
});
searchBtn.addEventListener("click", () => commitSearch());
clearBtn.addEventListener("click", () => {
searchInput.value = "";
state.keyword = "";
void load(true);
});
clearTagsBtn.addEventListener("click", () => clearTags());
searchInput.addEventListener("keydown", (ev) => {
if (ev.key === "Enter") commitSearch();
});
searchInput.addEventListener("change", () => commitSearch());
loadMoreBtn.addEventListener("click", () => void load(false));
clearGrid();
applyFiltersUI();
renderTagPicker();
root.textContent = "";
root.append(searchRow, filters, grid, sentinel, footer);
if (config.enableInfiniteScroll && "IntersectionObserver" in window) {
const io = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
if (state.loading || !state.hasNext) return;
void load(false);
}
});
io.observe(sentinel);
}
void load(true);
}
function initAll(container) {
if (!shouldInitOnThisPage()) return;
const base = container instanceof Element ? container : document;
const nodes = base.querySelectorAll(config.containerSelector);
for (const node of nodes) renderWidget(node);
}
function onReady(fn) {
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", fn);
else fn();
}
if (typeof window !== "undefined" && window.mw && typeof window.mw.hook === "function") {
window.mw.hook("wikipage.content").add(($content) => {
const root = ($content && $content[0]) || document;
initAll(root);
});
} else {
onReady(() => initAll(document));
}
})();
