匿名
未登录
创建账号
登录
Postal Wiki
搜索
查看“︁用户:Hehua/filepreview.js”︁的源代码
来自Postal Wiki
命名空间
用户页
讨论
更多
更多
页面操作
阅读
查看源代码
历史
用户贡献
←
用户:Hehua/filepreview.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您没有权限编辑此JavaScript页面,因为此页面包含另一位用户的个人设置。
您可以查看和复制此页面的源代码。
/** * FilePreview — 文件链接悬停预览脚本 * 鼠标悬停在 File: 蓝色链接上时,弹出浮窗显示: * - 缩略图预览 * - 文件信息(尺寸、大小、上传者) * - 分类 (categories) * - 版权/许可模板 (templates) * * 安装方式: * 将本脚本的内容复制到 User:<你的名字>/common.js * 或通过 importScript('User:你的名字/FilePreview.js'); 引入 */ mw.loader.using(['mediawiki.api', 'mediawiki.util', 'mediawiki.user'], function () { 'use strict'; console.log('[FilePreview] 脚本已加载'); var CONFIG = { delay: 400, thumbWidth: 220, maxPopupWidth: 460, maxPopupHeight: 520 }; var state = { link: null, fetchTimer: null, hideTimer: null, popup: null }; /* ---------- utils ---------- */ function isFileLink(link) { if (!link || !link.href) return false; var title = link.getAttribute('title') || ''; if (/^(File|Image):/i.test(title)) return true; return /[?&]title=(File|Image):/i.test(link.href); } function getFileTitle(link) { var title = link.getAttribute('title') || ''; var m = title.match(/^(File|Image):(.+)$/i); if (m) return m[1] + ':' + m[2]; var href = link.getAttribute('href') || ''; m = href.match(/[?&]title=(File|Image):([^&]+)/); if (m) return m[1] + ':' + decodeURIComponent(m[2].replace(/\+/g, ' ')); return null; } 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 esc(s) { return mw.html.escape(String(s)); } /* ---------- 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); clearTimeout(state.fetchTimer); }); el.addEventListener('mouseleave', function (e) { if (state.link && e.relatedTarget && state.link.contains(e.relatedTarget)) return; hidePopup(); }); } return state.popup; } function showPopup(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'; state.link = null; } /* ---------- API ---------- */ function fetchFileData(fileTitle) { var api = new mw.Api(); return api.get({ action: 'query', titles: fileTitle, prop: 'categories|templates|imageinfo', cllimit: 50, tllimit: 50, iiprop: 'url|size|user|comment|timestamp|extmetadata', iiurlwidth: CONFIG.thumbWidth, format: 'json' }); } /* ---------- render ---------- */ function renderPopup(data, x, y) { var pages = data.query && data.query.pages; if (!pages) { showPopup(x, y, '<div style="color:#c00;">无法获取数据</div>'); return; } var id = Object.keys(pages)[0]; var page = pages[id]; if (id === '-1' || !page) { showPopup(x, y, '<div style="color:#888;">文件页面不存在</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 licField = ii.extmetadata.LicenseShortName || ii.extmetadata.License || ii.extmetadata.Copyright; if (licField) { var licVal = licField.value || licField; parts.push('<div style="color:#555;margin-bottom:4px;font-size:12px;">\u8bb8\u53ef: ' + esc(String(licVal)) + '</div>'); } } } // categories if (page.categories && page.categories.length) { parts.push('<div style="margin-top:8px;font-weight:bold;font-size:13px;">\u5206\u7c7b</div>'); parts.push('<ul style="margin:2px 0 0 14px;padding:0;list-style:none;">'); 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>'); } // templates 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:130px;overflow-y:auto;">'); page.templates.slice(0, 40).forEach(function (t) { var name = t.title.replace(/^Template:/, ''); 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(name) + '}}</span>'); }); if (page.templates.length > 40) { parts.push('<span style="color:#888;font-size:11px;"> \u2026+' + (page.templates.length - 40) + '</span>'); } parts.push('</div>'); } // footer link 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(x, y, parts.join('')); } /* ---------- event handlers ---------- */ var currentMouseX = 0, currentMouseY = 0; document.addEventListener('mousemove', function (e) { currentMouseX = e.clientX; currentMouseY = e.clientY; }, true); function onLinkOver(e) { var link = e.target.closest ? e.target.closest('a') : null; if (!link || !isFileLink(link)) return; if (link === state.link) return; clearTimeout(state.fetchTimer); clearTimeout(state.hideTimer); state.link = link; var title = getFileTitle(link); if (!title) { console.log('[FilePreview] 无法解析文件标题:', link.href); return; } console.log('[FilePreview] 悬停:', title); var mx = currentMouseX, my = currentMouseY; state.fetchTimer = setTimeout(function () { showPopup(mx, my, '<div style="color:#888;font-size:13px;">\u52a0\u8f7d\u4e2d\u2026 ' + esc(title) + '</div>'); fetchFileData(title).then(function (data) { if (state.link === link) renderPopup(data, mx, my); }).catch(function (err) { console.log('[FilePreview] API 错误:', err); if (state.link === link) showPopup(mx, my, '<div style="color:#c00;">\u8bf7\u6c42\u5931\u8d25: ' + esc(String(err)) + '</div>'); }); }, CONFIG.delay); } function onLinkOut(e) { var link = e.target.closest ? e.target.closest('a') : null; if (!link || !isFileLink(link) || link !== state.link) return; // 如果鼠标移到了 <a> 内部的子元素(如 <img>),不隐藏 if (e.relatedTarget && link.contains(e.relatedTarget)) return; clearTimeout(state.fetchTimer); state.hideTimer = setTimeout(function () { hidePopup(); }, 200); } /* ---------- install ---------- */ document.addEventListener('mouseover', onLinkOver, true); document.addEventListener('mouseout', onLinkOut, true); window.addEventListener('scroll', function () { hidePopup(); }, true); console.log('[FilePreview] 事件监听已安装'); });
该页面使用的模板:
模板:' + esc(t.title.replace(/^Template:/, '')) + '
(
查看源代码
)
返回
用户:Hehua/filepreview.js
。
导航
导航
首页
讨论版
最近更改
随机页面
深色模式
帮助
规章制度
编辑规范
格式指导
管理员公示板
人员任免方针
沙盒
链接
QQ群
Discord社区服务器
wiki工具
wiki工具
特殊页面
页面工具
页面工具
用户页面工具
日志
查看用户组
更多
链入页面
相关更改
页面信息
页面日志