打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

MediaWiki:GeneralMdTocGen.js

MediaWiki界面页面

注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
// 使用豆包AI生成
// 等待页面完全加载(确保嵌入的 Markdown 内容已渲染)
$(document).ready(function() {
    // 仅在目标页面执行(根据实际 URL 调整)
    if (window.location.href.includes('EaseCation_Wiki:%E6%80%BB%E5%88%99')) {
        generateTOCFromMarkdownHeadings();
    }
});

function generateTOCFromMarkdownHeadings() {
    // 1. 获取嵌入的 Markdown 内容容器(根据插件渲染结果调整选择器)
    // 假设 External Content 插件将 Markdown 渲染到 class 为 "external-content" 的容器中
    const markdownContainer = document.querySelector('.external-content, #mw-content-text');
    if (!markdownContainer) return;

    // 2. 提取 Markdown 中通过 # 标识的标题(h1-h6 标签,对应 # 到 ######)
    // Markdown 渲染器通常会将 # 转换为 

,## 转换为

,以此类推 const headings = Array.from(markdownContainer.querySelectorAll('h1, h2, h3, h4, h5, h6')) .filter(heading => { // 过滤空标题 return heading.textContent.trim() !== ''; }) .map(heading => { // 解析层级(h1 → 1,h2 → 2,...,h6 → 6) const level = parseInt(heading.tagName.toLowerCase().replace('h', '')); // 生成唯一 ID(用于锚点跳转) const id = heading.id || `md-heading-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; heading.id = id; return { level: level, text: heading.textContent.trim(), id: id }; }); if (headings.length === 0) return; // 无标题时不生成 TOC // 3. 生成 MediaWiki 原生风格 TOC 结构 const tocContainer = document.createElement('div'); tocContainer.id = 'toc'; tocContainer.className = 'toc mw-toc'; tocContainer.innerHTML = `

目录

    `; const tocList = tocContainer.querySelector('#toc-list'); // 4. 构建层级目录(处理 h1-h6 的嵌套关系) let currentLevel = 1; // 初始层级从 h1 开始 let currentParent = tocList; // 当前列表容器(初始为根列表) const levelStack = [tocList]; // 存储各层级的列表容器,用于层级回退 headings.forEach(heading => { const { level, text, id } = heading; // 调整层级:加深(如 h2 → h3)或回退(如 h3 → h1) if (level > currentLevel) { // 层级加深:在当前最后一个列表项后创建子列表 const lastLi = currentParent.lastElementChild; if (lastLi) { const subList = document.createElement('ul'); subList.className = `mw-toc-list mw-toc-level-${level}`; lastLi.appendChild(subList); levelStack.push(subList); currentParent = subList; } } else if (level < currentLevel) { // 层级回退:从栈中弹出多余层级,回到对应父级 const stepsToBack = currentLevel - level; for (let i = 0; i < stepsToBack; i++) { levelStack.pop(); } currentParent = levelStack[levelStack.length - 1]; } // 生成目录项(带编号和锚点) const li = document.createElement('li'); li.className = `toclevel-${level}`; li.innerHTML = ` ${getTocNumber(heading, headings)} ${text} `; currentParent.appendChild(li); // 更新当前层级 currentLevel = level; }); // 5. 添加 TOC 折叠/展开功能(匹配 MediaWiki 原生交互) const toctitle = tocContainer.querySelector('#toctitle'); toctitle.addEventListener('click', () => { const isCollapsed = tocList.classList.contains('mw-toc-collapsed'); if (isCollapsed) { tocList.classList.remove('mw-toc-collapsed'); toctitle.querySelector('h2').textContent = '目录'; } else { tocList.classList.add('mw-toc-collapsed'); toctitle.querySelector('h2').textContent = '目录 [+]'; } }); // 6. 将 TOC 插入到页面正文顶部 const contentStart = markdownContainer.firstElementChild; if (contentStart) { markdownContainer.insertBefore(tocContainer, contentStart); } else { markdownContainer.appendChild(tocContainer); } } // 生成 MediaWiki 风格的目录编号(如 1, 1.1, 1.1.1...) function getTocNumber(heading, allHeadings) { const index = allHeadings.indexOf(heading); if (index === 0) return '1'; const numberParts = []; // 遍历当前标题之前的所有标题,计算层级编号 for (let i = 0; i <= index; i++) { const current = allHeadings[i]; if (current === heading) { // 找到同层级的上一个标题,编号 +1 let prevSibling = null; for (let j = i - 1; j >= 0; j--) { if (allHeadings[j].level === current.level) { prevSibling = allHeadings[j]; break; } } if (prevSibling) { const prevNum = getTocNumber(prevSibling, allHeadings); const lastPart = parseInt(prevNum.split('.').pop()); numberParts.push(lastPart + 1); } else { // 同层级第一个标题,编号为 1 numberParts.push(1); } break; } else if (current.level < heading.level) { // 继承父层级编号(如 h3 继承 h2 的编号前缀) const parentNum = getTocNumber(current, allHeadings); if (!numberParts.includes(parentNum)) { numberParts.push(...parentNum.split('.')); } } } return numberParts.join('.'); }