查看“︁MediaWiki:Common.js”︁的源代码
←
MediaWiki:Common.js
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
/* 虾仁维基 - 自定义侧边栏导航 v2.1 */ /* 优化:古风主题统一、健壮初始化、精致样式 */ /* 最后更新: 2026-07-30 */ (function ($, mw) { 'use strict'; var COLLAPSE_KEY = 'xiarenwiki-nav-v2'; var WORKS = ['我在大明那些年', '彼岸轮回', '一品布衣']; var WORK_DIRECT = ['宇宙层', '人物', '世界观', '设定']; function init() { var wgIsArticle = mw.config.get('wgIsArticle'); var wgCanonicalSpecialPageName = mw.config.get('wgCanonicalSpecialPageName'); if (!wgIsArticle && wgCanonicalSpecialPageName) { return; } mw.loader.using('mediawiki.api').then(function () { waitForPanel(function ($panel) { buildNav($panel); }); }).catch(function (e) { console.error('[虾仁导航] 依赖加载失败,降级构建', e); waitForPanel(function ($panel) { buildNav($panel); }); }); } function waitForPanel(cb) { var $panel = $('#mw-panel'); if ($panel.length) return cb($panel); var tries = 0; var timer = setInterval(function () { $panel = $('#mw-panel'); if ($panel.length || ++tries > 50) { clearInterval(timer); if ($panel.length) cb($panel); } }, 100); } function buildNav($panel) { var html = ''; html += '<div class="xn-search">'; html += '<form action="' + mw.util.getUrl('Special:Search') + '" method="get">'; html += '<input type="text" name="search" class="xn-search-input" placeholder="检索典籍…" />'; html += '</form></div>'; html += section('Wiki', [ ['首页', '首页'], ['Wiki简介', 'Wiki简介'], ['管理员告示', '管理员告示'], ['随机页面', 'Special:Random'], ['快速搜索', 'Special:Search'], ['相关平台', '相关平台'], ['Wiki源站点', 'Wiki源站点'] ]); html += section('虾仁简介', [ ['虾仁?', '虾仁?'], ['虾仁共创收录规则', '虾仁共创收录规则'], ['虾仁宇宙结构介绍', '虾仁宇宙结构介绍'] ]); html += '<div class="xn-section">'; html += '<div class="xn-header xn-expandable" data-sid="universe">虾仁宇宙</div>'; html += '<div class="xn-body" id="xn-universe"><div class="xn-loading">卷帙加载中…</div></div>'; html += '</div>'; html += '<div class="xn-section">'; html += '<div class="xn-header xn-expandable" data-sid="literature">虾仁文学</div>'; html += '<div class="xn-body" id="xn-literature">'; html += link('创始宣言', '创始宣言'); html += link('虾仁六章', '虾仁六章'); html += link('虾仁异志', '虾仁异志'); html += link('虾仁诗作', '虾仁诗作'); html += link('虾仁音乐', '虾仁音乐'); html += '<div class="xn-subsection">'; html += '<div class="xn-subheader xn-expandable" data-sid="papers">虾仁论文 ' + plus('虾仁论文') + '</div>'; html += '<div class="xn-subbody" id="xn-papers">'; html += link('去中心化创作模式的研究', '去中心化创作模式的研究'); html += link('数字时代的孙悟空', '数字时代的孙悟空'); html += '</div></div></div></div>'; html += section('虾仁历史', [ ['起源', '虾仁历史/起源'], ['传播', '虾仁历史/传播'], ['转折', '虾仁历史/转折'], ['爆发', '虾仁历史/爆发'], ['危机', '虾仁历史/危机'], ['转型', '虾仁历史/转型'] ]); html += '<div class="xn-single"><a href="' + url('共创入口') + '">共创入口</a></div>'; $panel.html(html); restoreCollapse(); bindEvents(); highlightCurrent(); loadUniverse(); } function section(title, items) { var sid = title.replace(/[^a-z0-9\u4e00-\u9fff]/gi, '').toLowerCase(); var h = '<div class="xn-section">'; h += '<div class="xn-header xn-expandable" data-sid="' + sid + '">' + title + '</div>'; h += '<div class="xn-body" id="xn-' + sid + '">'; for (var i = 0; i < items.length; i++) { h += link(items[i][0], items[i][1]); } h += '</div></div>'; return h; } function link(label, page, cls) { return '<div class="xn-link' + (cls ? ' ' + cls : '') + '"><a href="' + url(page) + '">' + label + '</a></div>'; } function url(page) { return mw.util.getUrl(page); } function plus(page) { return '<a class="xn-plus" href="' + url(page) + '?action=edit" title="编辑/新增">+</a>'; } async function loadUniverse() { var $body = $('#xn-universe'); if (!$body.length) return; try { var api = new mw.Api(); var html = ''; for (var i = 0; i < WORKS.length; i++) { var work = WORKS[i]; var workSid = 'work' + i; var subpages = []; try { var result = await api.get({ action: 'query', list: 'allpages', apprefix: work + '/', aplimit: 100 }); subpages = result.query.allpages || []; } catch (e) { console.error('[虾仁导航] API error for ' + work, e); } html += '<div class="xn-work">'; html += '<div class="xn-work-title xn-expandable" data-sid="' + workSid + '">' + work + '</div>'; html += '<div class="xn-body" id="xn-' + workSid + '">'; var directSet = {}; for (var j = 0; j < subpages.length; j++) { var rel = subpages[j].title.substring(work.length + 1); if (rel.indexOf('/') === -1) directSet[rel] = true; } for (var k = 0; k < WORK_DIRECT.length; k++) { var item = WORK_DIRECT[k]; var exists = directSet[item]; html += link(item, work + '/' + item, exists ? '' : 'xn-missing'); } var plotSegs = []; for (j = 0; j < subpages.length; j++) { rel = subpages[j].title.substring(work.length + 1); var parts = rel.split('/'); if (parts.length === 2 && parts[0] === '剧情层') { plotSegs.push(parts[1]); } } var plotSid = workSid + 'plot'; html += '<div class="xn-subsection">'; html += '<div class="xn-subheader xn-expandable" data-sid="' + plotSid + '">剧情层 ' + plus(work + '/剧情层') + '</div>'; html += '<div class="xn-subbody" id="xn-' + plotSid + '">'; for (k = 0; k < plotSegs.length; k++) { var seg = plotSegs[k]; var segSid = workSid + 'seg' + k; var segPage = work + '/剧情层/' + seg; var jinji = []; try { var segResult = await api.get({ action: 'query', list: 'allpages', apprefix: segPage + '/', aplimit: 50 }); var segPages = segResult.query.allpages || []; for (var m = 0; m < segPages.length; m++) { jinji.push(segPages[m].title.substring(segPage.length + 1)); } } catch (e2) {} html += '<div class="xn-subsubsection">'; html += '<div class="xn-subsubheader xn-expandable" data-sid="' + segSid + '">' + seg + ' ' + plus(segPage) + '</div>'; html += '<div class="xn-subsubbody" id="xn-' + segSid + '">'; for (m = 0; m < jinji.length; m++) { html += link(jinji[m], segPage + '/' + jinji[m]); } html += '</div></div>'; } html += '</div></div>'; html += '</div></div>'; } html += '<div class="xn-link xn-add-work"><a href="' + url('Special:Search') + '" title="搜索已有作品">+ 发现更多作品</a></div>'; $body.html(html); restoreCollapse(); bindEvents(); highlightCurrent(); } catch (e) { console.error('[虾仁导航] 虾仁宇宙加载失败', e); $body.html('<div class="xn-link">(加载失败,请刷新)</div>'); } } function highlightCurrent() { var currentTitle = mw.config.get('wgPageName'); $('#mw-panel .xn-link a').each(function () { var href = $(this).attr('href'); if (!href) return; var match = false; if (href.indexOf('title=') > 0) { var m = href.match(/title=([^&]+)/); if (m) match = decodeURIComponent(m[1]) === currentTitle; } else { var parts = href.split('/'); var last = parts[parts.length - 1]; match = decodeURIComponent(last) === currentTitle; } if (match) { $(this).addClass('xn-active'); $(this).closest('.xn-link').addClass('xn-active-link'); $(this).parents('.xn-body, .xn-subbody, .xn-subsubbody').each(function () { $(this).show(); var sid = $(this).attr('id'); if (sid && sid.indexOf('xn-') === 0) { sid = sid.substring(3); $('[data-sid="' + sid + '"]').removeClass('xn-collapsed'); } }); } }); } function bindEvents() { $(document).off('click.xn').on('click.xn', '.xn-expandable', function (e) { if ($(e.target).closest('.xn-plus').length) return; var sid = $(this).data('sid'); var $body = $('#xn-' + sid); if (!$body.length) $body = $(this).next('.xn-body,.xn-subbody,.xn-subsubbody'); if (!$body.length) return; $body.slideToggle(150); $(this).toggleClass('xn-collapsed', !$body.is(':visible')); var state = loadState(); state[sid] = $body.is(':visible'); saveState(state); }); } function restoreCollapse() { var state = loadState(); var defaults = { 'universe': true }; for (var key in defaults) { if (!(key in state)) state[key] = defaults[key]; } Object.keys(state).forEach(function (sid) { var $header = $('[data-sid="' + sid + '"]'); var $body = $('#xn-' + sid); if (!$body.length) $body = $header.next('.xn-body,.xn-subbody,.xn-subsubbody'); if (!$body.length) return; if (state[sid]) { $body.show(); $header.removeClass('xn-collapsed'); } else { $body.hide(); $header.addClass('xn-collapsed'); } }); } function loadState() { try { return JSON.parse(localStorage.getItem(COLLAPSE_KEY) || '{}'); } catch (e) { return {}; } } function saveState(s) { try { localStorage.setItem(COLLAPSE_KEY, JSON.stringify(s)); } catch (e) {} } $(init); })(jQuery, mediaWiki); /* ===== 虾仁AI 浮窗助手(2026-07-30 v2) ===== */ (function () { if (window.__xrAiInited) return; window.__xrAiInited = true; function xrAvatar(size) { return '<svg viewBox="0 0 48 48" width="' + size + '" height="' + size + '" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><ellipse cx="24" cy="14.5" rx="18" ry="5.5" fill="#caa53d"/><ellipse cx="24" cy="14.5" rx="18" ry="5.5" fill="none" stroke="#a8842a" stroke-width="0.8"/><path d="M13 14.5 Q24 2.5 35 14.5 Z" fill="#d9b84a"/><path d="M13 14.5 Q24 2.5 35 14.5 Z" fill="none" stroke="#a8842a" stroke-width="0.8"/><circle cx="12.5" cy="25" r="6.5" fill="#2c2c2c"/><circle cx="35.5" cy="25" r="6.5" fill="#2c2c2c"/><circle cx="24" cy="29" r="15" fill="#fdfdfd" stroke="#e9e2d2" stroke-width="0.8"/><ellipse cx="18" cy="28" rx="4.5" ry="5.6" fill="#2c2c2c"/><ellipse cx="30" cy="28" rx="4.5" ry="5.6" fill="#2c2c2c"/><circle cx="18" cy="28" r="1.9" fill="#fff"/><circle cx="30" cy="28" r="1.9" fill="#fff"/><ellipse cx="24" cy="33" rx="2.1" ry="1.5" fill="#2c2c2c"/><path d="M20.5 36 Q24 38.5 27.5 36" stroke="#2c2c2c" stroke-width="1.3" fill="none" stroke-linecap="round"/><circle cx="15" cy="33" r="2" fill="#c41e3a" opacity="0.18"/><circle cx="33" cy="33" r="2" fill="#c41e3a" opacity="0.18"/></svg>'; } function init() { var API = '/ai_proxy.php'; var TITLE = '虾仁AI'; var css = document.createElement('style'); css.textContent = [ '#xr-ai-fab{position:fixed;right:22px;bottom:22px;z-index:99999;width:56px;height:56px;border-radius:50%;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;background:linear-gradient(135deg,#c41e3a,#9b182d);color:#fff;font-size:26px;box-shadow:0 6px 20px rgba(155,24,45,.4);transition:transform .2s ease,box-shadow .2s ease;font-family:"Noto Serif SC","Songti SC",serif}', '#xr-ai-fab:hover{transform:scale(1.08);box-shadow:0 8px 26px rgba(155,24,45,.55)}', '#xr-ai-panel{position:fixed;right:22px;bottom:90px;z-index:99999;width:360px;max-width:calc(100vw - 32px);height:520px;max-height:calc(100vh - 120px);display:none;flex-direction:column;overflow:hidden;background:#fbf6ec;border:1px solid #e7d8bf;border-radius:14px;box-shadow:0 12px 40px rgba(80,40,30,.25);font-family:"Noto Serif SC","Source Han Serif SC","Songti SC","STSong","SimSun",serif;color:#3a2418}', '#xr-ai-panel.xr-show{display:flex}', '.xr-ai-head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;background:linear-gradient(135deg,#c41e3a,#9b182d);color:#fff}', '.xr-ai-title{font-weight:700;font-size:16px;letter-spacing:.05em;display:flex;align-items:center;gap:6px}', '.xr-ai-close{background:none;border:none;color:#fff;font-size:20px;cursor:pointer;line-height:1}', '.xr-ai-tabs{display:flex;border-bottom:1px solid #ecdfc8;background:#f3e9d6}', '.xr-ai-tab{flex:1;padding:9px 0;text-align:center;cursor:pointer;font-size:13px;color:#7a5a3a;border:none;background:none;transition:color .2s}', '.xr-ai-tab.xr-active{color:#c41e3a;font-weight:700;box-shadow:inset 0 -2px 0 #c41e3a}', '.xr-ai-hint{text-align:center;font-size:11px;color:#a98c6b;padding:0 0 6px}', '.xr-ai-msgs{flex:1;overflow-y:auto;padding:14px;display:flex;flex-direction:column;gap:10px}', '.xr-ai-msg{max-width:84%;padding:9px 12px;border-radius:12px;line-height:1.6;font-size:14px;white-space:pre-wrap;word-break:break-word}', '.xr-ai-msg.xr-user{align-self:flex-end;background:#c41e3a;color:#fff;border-bottom-right-radius:3px}', '.xr-ai-msg.xr-ai{align-self:flex-start;background:#fff;color:#3a2418;border:1px solid #ecdfc8;border-left:3px solid #c41e3a;border-bottom-left-radius:3px}', '.xr-ai-inputbar{display:flex;gap:8px;padding:10px;border-top:1px solid #ecdfc8;background:#f6eddb}', '.xr-ai-input{flex:1;resize:none;border:1px solid #e0cda8;border-radius:9px;padding:8px 10px;font-family:inherit;font-size:14px;background:#fff;outline:none;max-height:80px}', '.xr-ai-input:focus{border-color:#c41e3a}', '.xr-ai-send{border:none;border-radius:9px;padding:0 16px;background:#9b182d;color:#fff;cursor:pointer;font-family:inherit;font-size:14px;transition:background .2s}', '.xr-ai-send:hover{background:#c41e3a}', '.xr-ai-send:disabled{opacity:.5;cursor:default}' ].join('\n'); document.head.appendChild(css); var fab = document.createElement('button'); fab.id = 'xr-ai-fab'; fab.innerHTML = xrAvatar(38); fab.title = TITLE; fab.setAttribute('aria-label', TITLE); var panel = document.createElement('div'); panel.id = 'xr-ai-panel'; panel.innerHTML = '<div class="xr-ai-head"><span class="xr-ai-title">' + xrAvatar(22) + ' ' + TITLE + '</span>' + '<button class="xr-ai-close" title="收起">×</button></div>' + '<div class="xr-ai-tabs">' + '<button class="xr-ai-tab xr-active" data-mode="general">闲聊</button>' + '<button class="xr-ai-tab" data-mode="wiki">问虾仁宇宙</button></div>' + '<div class="xr-ai-hint">内容由 AI 生成,仅供参考</div>' + '<div class="xr-ai-msgs"></div>' + '<div class="xr-ai-inputbar">' + '<textarea class="xr-ai-input" rows="1" placeholder="和虾仁AI说点什么…"></textarea>' + '<button class="xr-ai-send">发送</button></div>' + '<input type="text" name="company" tabindex="-1" autocomplete="off" ' + 'style="position:absolute;left:-9999px;width:1px;height:1px;opacity:0;" aria-hidden="true">'; document.body.appendChild(fab); document.body.appendChild(panel); var msgsEl = panel.querySelector('.xr-ai-msgs'); var inputEl = panel.querySelector('.xr-ai-input'); var sendEl = panel.querySelector('.xr-ai-send'); var closeEl = panel.querySelector('.xr-ai-close'); var tabs = panel.querySelectorAll('.xr-ai-tab'); var honey = panel.querySelector('input[name=company]'); var mode = 'general'; var history = []; var busy = false; fab.addEventListener('click', function () { panel.classList.toggle('xr-show'); }); closeEl.addEventListener('click', function () { panel.classList.remove('xr-show'); }); tabs.forEach(function (t) { t.addEventListener('click', function () { tabs.forEach(function (x) { x.classList.remove('xr-active'); }); t.classList.add('xr-active'); mode = t.getAttribute('data-mode'); }); }); function scrollBottom() { msgsEl.scrollTop = msgsEl.scrollHeight; } function addBubble(cls, text) { var d = document.createElement('div'); d.className = 'xr-ai-msg ' + cls; d.textContent = text; msgsEl.appendChild(d); scrollBottom(); return d; } function callAI(msgs, m, onChunk) { return fetch(API, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ mode: m, messages: msgs, company: honey.value }) }).then(function (res) { if (!res.ok) throw new Error('HTTP ' + res.status); var reader = res.body.getReader(); var decoder = new TextDecoder(); var buf = ''; function pump() { return reader.read().then(function (result) { if (result.done) return; buf += decoder.decode(result.value, { stream: true }); var idx; while ((idx = buf.indexOf('\n')) >= 0) { var line = buf.slice(0, idx).trim(); buf = buf.slice(idx + 1); if (!line) continue; try { var obj = JSON.parse(line); if (obj.content) onChunk(obj.content); if (obj.error) onChunk('(' + obj.error + ')'); } catch (e) {} } return pump(); }); } return pump(); }); } function send() { var text = inputEl.value.trim(); if (!text || busy) return; busy = true; sendEl.disabled = true; addBubble('xr-user', text); history.push({ role: 'user', content: text }); inputEl.value = ''; var aiBubble = addBubble('xr-ai', '…'); var acc = ''; callAI(history.slice(-12), mode, function (chunk) { acc += chunk; aiBubble.textContent = acc + '▌'; scrollBottom(); }).then(function () { aiBubble.textContent = acc || '(暂无回复)'; history.push({ role: 'assistant', content: acc }); busy = false; sendEl.disabled = false; scrollBottom(); }).catch(function (e) { aiBubble.textContent = '出错了:' + (e && e.message ? e.message : e); busy = false; sendEl.disabled = false; }); } sendEl.addEventListener('click', send); inputEl.addEventListener('keydown', function (e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }); addBubble('xr-ai', '你好,我是虾仁AI,可以陪你闲聊,也能帮你查「虾仁宇宙」的资料。选个模式开始吧~'); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();
返回
MediaWiki:Common.js
。
导航菜单
个人工具
未登录
讨论
贡献
创建账号
登录
associated-pages
系统消息
讨论
English
查看
阅读
查看源代码
查看历史
更多
搜索
虾仁维基
首页
作品总录
三部奠基作品
我在大明那些年
彼岸轮回
一品布衣
文献典藏
虾仁六章
虾仁·传播史
共创入口
工具
最近更改
随机页面
搜索
工具
链入页面
相关更改
页面信息