匿名
未登录
创建账号
登录
Postal Wiki
搜索
查看“︁用户:Hehua/filepreview.js”︁的源代码
来自Postal Wiki
命名空间
用户页
讨论
更多
更多
页面操作
阅读
查看源代码
历史
用户贡献
←
用户:Hehua/filepreview.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您没有权限编辑此JavaScript页面,因为此页面包含另一位用户的个人设置。
您可以查看和复制此页面的源代码。
/** * FilePreview — 文件链接悬停预览脚本 * 鼠标悬停在 File: 蓝色链接上时,弹出浮窗显示: * - 缩略图预览 * - 文件信息(尺寸、大小、上传者) * - 分类 (categories) * - 版权/许可模板 (templates) * * 安装方式: * 将本脚本的内容复制到 User:<你的名字>/common.js * 或通过 importScript('User:你的名字/FilePreview.js'); 引入 */ (function () { 'use strict'; if (!window.mw || !mw.loader) return; mw.loader.using(['mediawiki.api', 'mediawiki.util'], function () { var CONFIG = { delay: 400, thumbWidth: 220, maxPopupWidth: 480, maxPopupHeight: 540 }; var state = { fetchTimer: null, hideTimer: null, popup: null }; /* ---------- localized namespace for File (NS 6) ---------- */ function getFileNSNames() { var names = ['File', 'Image']; var fmt = mw.config.get('wgFormattedNamespaces') || {}; if (fmt[6] && names.indexOf(fmt[6]) === -1) names.push(fmt[6]); var aliases = mw.config.get('wgNamespaceAliases') || {}; for (var a in aliases) { if (aliases[a] === 6 && names.indexOf(a) === -1) names.push(a); } return names; } var fileNSNames = getFileNSNames(); var fileNSRe = new RegExp('^(' + fileNSNames.map(function (n) { return n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }).join('|') + '):(.+)$', 'i'); var fileCSSsel = fileNSNames.map(function (n) { return 'a[title^="' + n + ':"]'; }).join(','); /* ---------- utils ---------- */ function esc(s) { return mw.html.escape(String(s)); } function fmtBytes(b) { if (!b) return '?'; if (b < 1024) return b + ' B'; if (b < 1048576) return (b / 1024).toFixed(1) + ' KB'; return (b / 1048576).toFixed(1) + ' MB'; } function getFileTitle(link) { var t = link.getAttribute('title') || ''; var m = t.match(fileNSRe); if (m) return 'File:' + m[2]; var h = link.getAttribute('href') || ''; m = h.match(/[?&]title=(File|Image):([^&]+)/); if (m) return 'File:' + decodeURIComponent(m[2].replace(/\+/g, ' ')); return null; } /* ---------- popup ---------- */ function getPopup() { if (!state.popup) { var el = document.createElement('div'); el.id = 'filepreview-popup'; el.style.cssText = [ 'display:none;position:fixed;z-index:9999', 'background:#fff', 'border:1px solid #c8ccd1', 'border-radius:6px', 'box-shadow:0 4px 16px rgba(0,0,0,0.2)', 'padding:14px', 'max-width:' + CONFIG.maxPopupWidth + 'px', 'max-height:' + CONFIG.maxPopupHeight + 'px', 'overflow-y:auto', 'font:13px/1.5 sans-serif', 'color:#222' ].join(';'); document.body.appendChild(el); state.popup = el; el.addEventListener('mouseenter', function () { clearTimeout(state.hideTimer); }); el.addEventListener('mouseleave', function () { state.hideTimer = setTimeout(hidePopup, 300); }); } return state.popup; } function showPopup(link, x, y, html) { var popup = getPopup(); popup.innerHTML = html; popup.style.display = 'block'; var rect = popup.getBoundingClientRect(); var left = Math.max(6, Math.min(x + 12, window.innerWidth - rect.width - 6)); var top = Math.max(6, Math.min(y + 12, window.innerHeight - rect.height - 6)); popup.style.left = left + 'px'; popup.style.top = top + 'px'; } function hidePopup() { clearTimeout(state.hideTimer); clearTimeout(state.fetchTimer); if (state.popup) state.popup.style.display = 'none'; } /* ---------- api + render ---------- */ function fetchData(title) { return new mw.Api().get({ action: 'query', titles: title, prop: 'categories|templates|imageinfo', cllimit: 50, tllimit: 50, iiprop: 'url|size|user|comment|timestamp|extmetadata', iiurlwidth: CONFIG.thumbWidth, format: 'json' }); } function render(data, link, x, y) { var pages = data.query && data.query.pages; if (!pages) { showPopup(link, x, y, '<div style="color:#c00;">\u65e0\u6cd5\u83b7\u53d6\u6570\u636e</div>'); return; } var id = Object.keys(pages)[0], page = pages[id]; if (id === '-1' || !page) { showPopup(link, x, y, '<div style="color:#888;">\u6587\u4ef6\u9875\u4e0d\u5b58\u5728</div>'); return; } var parts = []; parts.push('<div style="font-weight:bold;font-size:14px;margin-bottom:6px;word-break:break-all;">' + esc(page.title) + '</div>'); var ii = page.imageinfo && page.imageinfo[0]; if (ii) { if (ii.thumburl) { parts.push('<div style="text-align:center;margin-bottom:8px;"><a href="' + esc(ii.url) + '" target="_blank">' + '<img src="' + esc(ii.thumburl) + '" alt="" style="max-width:100%;border:1px solid #eaecf0;border-radius:3px;"></a></div>'); } var meta = []; if (ii.width && ii.height) meta.push(ii.width + '\u00d7' + ii.height + ' (' + fmtBytes(ii.size) + ')'); if (ii.user) meta.push('\u4e0a\u4f20\u8005: ' + esc(ii.user)); if (meta.length) parts.push('<div style="color:#555;margin-bottom:4px;font-size:12px;">' + meta.join(' | ') + '</div>'); if (ii.extmetadata) { var lf = ii.extmetadata.LicenseShortName || ii.extmetadata.License || ii.extmetadata.Copyright; if (lf) parts.push('<div style="color:#555;margin-bottom:4px;font-size:12px;">\u8bb8\u53ef: ' + esc(String(lf.value || lf)) + '</div>'); } } if (page.categories && page.categories.length) { parts.push('<div style="margin-top:8px;font-weight:bold;font-size:13px;">\u5206\u7c7b</div><ul style="margin:2px 0 0 14px;padding:0;">'); page.categories.slice(0, 25).forEach(function (c) { parts.push('<li style="padding:1px 0;font-size:12px;">\u2022 ' + esc(c.title.replace(/^Category:/, '')) + '</li>'); }); if (page.categories.length > 25) parts.push('<li style="color:#888;font-size:12px;">\u2026\u8fd8\u6709' + (page.categories.length - 25) + '\u4e2a</li>'); parts.push('</ul>'); } else { parts.push('<div style="margin-top:6px;color:#888;font-size:12px;">\u65e0\u5206\u7c7b</div>'); } if (page.templates && page.templates.length) { parts.push('<div style="margin-top:8px;font-weight:bold;font-size:13px;">\u6a21\u677f(\u542b\u7248\u6743/\u8bb8\u53ef)</div>'); parts.push('<div style="margin:2px 0 0;max-height:140px;overflow-y:auto;">'); page.templates.slice(0, 40).forEach(function (t) { parts.push('<span style="display:inline-block;background:#f0f2f5;border:1px solid #d4d8dd;border-radius:3px;padding:1px 5px;margin:1px 2px;font:12px monospace;color:#333;">{{' + esc(t.title.replace(/^Template:/, '')) + '}}</span>'); }); if (page.templates.length > 40) parts.push('<span style="color:#888;font-size:11px;">\u2026+' + (page.templates.length - 40) + '</span>'); parts.push('</div>'); } parts.push('<div style="margin-top:10px;border-top:1px solid #eaecf0;padding-top:6px;text-align:right;font-size:12px;">' + '<a href="' + mw.util.getUrl(page.title) + '" target="_blank">\u6253\u5f00\u6587\u4ef6\u9875 \u2192</a></div>'); showPopup(link, x, y, parts.join('')); } /* ---------- bind ---------- */ function bindLink(link) { if (link._filePreview) return; link._filePreview = true; link.addEventListener('mouseenter', function (e) { clearTimeout(state.fetchTimer); clearTimeout(state.hideTimer); var title = getFileTitle(link); if (!title) return; var x = e.clientX, y = e.clientY; state.fetchTimer = setTimeout(function () { showPopup(link, x, y, '<div style="color:#888;">\u52a0\u8f7d\u4e2d\u2026 ' + esc(title) + '</div>'); fetchData(title).then(function (d) { render(d, link, x, y); }) .catch(function (err) { showPopup(link, x, y, '<div style="color:#c00;">\u5931\u8d25: ' + esc(String(err)) + '</div>'); }); }, CONFIG.delay); }); link.addEventListener('mouseleave', function () { clearTimeout(state.fetchTimer); state.hideTimer = setTimeout(hidePopup, 200); }); } function scanLinks() { document.querySelectorAll(fileCSSsel).forEach(bindLink); } /* ---------- init ---------- */ var observer = new MutationObserver(scanLinks); observer.observe(document.body, { childList: true, subtree: true }); scanLinks(); window.addEventListener('scroll', hidePopup, true); }); })();
该页面使用的模板:
模板:' + esc(t.title.replace(/^Template:/, '')) + '
(
查看源代码
)
返回
用户:Hehua/filepreview.js
。
导航
导航
首页
讨论版
最近更改
随机页面
深色模式
帮助
规章制度
编辑规范
格式指导
管理员公示板
人员任免方针
沙盒
链接
QQ群
Discord社区服务器
wiki工具
wiki工具
特殊页面
页面工具
页面工具
用户页面工具
日志
查看用户组
更多
链入页面
相关更改
页面信息
页面日志