跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
分类索引
最近更改
随便看看
灵兰秘典
捐助本站
帮助
帮助
联系我们
关于本站
MediaWiki帮助
中医百科
搜索
搜索
外观
登录
个人工具
登录
查看“︁MediaWiki:Gadget-UnihanTooltips.js”︁的源代码
系统消息
讨论
English
阅读
查看源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
查看源代码
查看历史
清除缓存
常规
链入页面
相关更改
特殊页面
页面信息
Cargo数据
短URL
外观
移至侧栏
隐藏
←
MediaWiki:Gadget-UnihanTooltips.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。 如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
/* 本小工具可以將[[Template:僻字]]的提示由原來的title提示改為元素式彈出提示,使觸控式裝置可以觀看有關提示 适配说明:兼容MediaWiki 1.43+,修复模块依赖错误,移除jquery.ui.animate依赖,优化动画逻辑 */ // 显式传入jQuery和mediaWiki,避免$冲突 (function($, mw) { "use strict"; /*===== 初始化检查:控制工具是否加载 =====*/ // 获取URL参数"UTdontload"(0=清除不加载状态,数字=设置不加载状态) const dontLoadParam = mw.util.getParamValue("UTdontload"); if (dontLoadParam !== null) { const paramVal = parseInt(dontLoadParam, 10); if (!isNaN(paramVal)) { paramVal === 0 ? mw.storage.remove("UTdontload") : mw.storage.set("UTdontload", "1"); } } // 若本地存储存在"不加载"状态,直接终止 if (mw.storage.get("UTdontload") === "1") { return; } /*===== 主初始化:命名空间与容器 =====*/ const canonicalNamespace = mw.config.get("wgCanonicalNamespace"); const allowedNamespaces = ["", "Project", "Help"]; // 主/项目/帮助命名空间 if (!allowedNamespaces.includes(canonicalNamespace)) { return; } // 获取内容容器(优先mw-content-text,兼容旧版本) const $bodyContent = $("#mw-content-text").length ? $("#mw-content-text") : $("body"); const bodyContent = $bodyContent[0]; /*===== 设备类型检测 =====*/ const isTouchscreen = window.matchMedia("(hover: none), (pointer: coarse)").matches || mw.config.get("wgDisplayResolution") === "mobile" || "ontouchstart" in document.documentElement; const hoverDelay = isTouchscreen ? 0 : 200; // 触摸设备无延迟 /*===== 工具函数:弹窗核心逻辑 =====*/ /** * 初始化元素数据(存储到元素data中) */ function initElementData(element) { let tooltipData = $(element).data("tooltipData"); if (!tooltipData) { const originalTitle = element.title || ""; element.title = ""; // 清空原生title提示 $(element).addClass("UHTarget"); // 添加高亮类 tooltipData = { originalTitle: originalTitle, tooltipNode: null, hideTimer: null, showTimer: null }; $(element).data("tooltipData", tooltipData); } return tooltipData; } /** * 创建弹窗内容(支持多行文本分割) */ function createContentElement(originalTitle) { const $contentContainer = $("<div>"); originalTitle.split("\n").forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { $contentContainer.append($("<p>").text(trimmedLine)); } }); return $contentContainer[0]; } /** * 创建弹窗DOM结构(包含内容区和箭头) */ function createTooltipNode(originalTitle) { const tooltipNode = document.createElement("ul"); tooltipNode.className = "unihantooltip"; // 内容区(包含提示文本和设置图标) const $contentLi = $("<li>"); const contentElement = createContentElement(originalTitle); const $settingsIcon = $("<div>") .addClass("UHsettings") .attr("title", "设置") .on("click", (e) => { e.stopPropagation(); // 示例:设置功能入口 alert("僻字提示设置(可扩展)"); }); // 组装内容区和箭头 $contentLi.append(contentElement).append($settingsIcon); const $arrowLi = $("<li>"); $(tooltipNode).append($contentLi).append($arrowLi); // 非触摸设备:绑定弹窗悬停事件 if (!isTouchscreen) { const tooltipData = { hideTimer: null, showTimer: null }; $(tooltipNode).data("tooltipData", tooltipData) .on("mouseenter", function() { showTooltip($(this).data("tooltipData"), this); }) .on("mouseleave", function() { hideTooltip($(this).data("tooltipData"), this); }); } return tooltipNode; } /** * 弹窗定位(避免超出视口,精准对齐) */ function positionTooltip(element, tooltipNode) { const $element = $(element); const $tooltip = $(tooltipNode); // 离线计算尺寸(避免布局抖动) $tooltip.css({ visibility: "hidden", display: "block" }).appendTo(bodyContent); // 元素与视口信息 const elementOffset = $element.offset(); const elementWidth = $element.outerWidth(); const elementHeight = $element.outerHeight(); const tooltipWidth = $tooltip.outerWidth(); const contentHeight = $tooltip.find("li:first-child").outerHeight(); const arrowHeight = 12; // 与CSS箭头高度一致 const viewport = { top: $(window).scrollTop(), bottom: $(window).scrollTop() + $(window).height(), left: 0, right: $(window).width() }; // 垂直定位(优先上方,不足则翻转) let top = elementOffset.top - contentHeight - arrowHeight; const needFlip = top < viewport.top || (elementOffset.top + contentHeight + arrowHeight) > viewport.bottom; $tooltip.toggleClass("UHflipped", needFlip); if (needFlip) { top = elementOffset.top + elementHeight + arrowHeight - 2; // 适配CSS翻转间距 } top = Math.max(viewport.top, Math.min(top, viewport.bottom - contentHeight)); // 水平定位(居中对齐,留边距) let left = elementOffset.left + (elementWidth - tooltipWidth) / 2; left = Math.max(viewport.left + 10, Math.min(left, viewport.right - tooltipWidth - 10)); // 箭头定位(指向元素中心) const arrowOffset = elementOffset.left - left + elementWidth / 2 - 7; $tooltip.find("li:last-child").css("margin-inline-start", `${arrowOffset}px`); // 应用定位并显示 $tooltip.css({ top: `${top}px`, left: `${left}px`, visibility: "visible", display: "" }); } /** * 显示弹窗(依赖CSS过渡,无JS动画依赖) */ function showTooltip(tooltipData, tooltipNode) { const $tooltip = $(tooltipNode); // 确保弹窗已插入DOM if (!tooltipNode.parentNode || tooltipNode.parentNode.nodeType === 11) { bodyContent.appendChild(tooltipNode); } // 添加可见类(触发CSS渲染) $tooltip.addClass("is-visible"); // 直接设置透明度(CSS过渡自动处理动画) $tooltip.stop().css("opacity", 1); // 清除隐藏定时器 if (tooltipData.hideTimer) { clearTimeout(tooltipData.hideTimer); tooltipData.hideTimer = null; } } /** * 隐藏弹窗(依赖CSS过渡,无JS动画依赖) */ function hideTooltip(tooltipData, tooltipNode) { const $tooltip = $(tooltipNode); // 清除显示定时器 if (tooltipData.showTimer) { clearTimeout(tooltipData.showTimer); tooltipData.showTimer = null; } // 延迟隐藏(防误触) tooltipData.hideTimer = setTimeout(() => { // 触发淡出(CSS过渡处理) $tooltip.stop().css("opacity", 0); // 过渡结束后清理 setTimeout(() => { $tooltip.removeClass("is-visible"); if (bodyContent.contains(tooltipNode)) { bodyContent.removeChild(tooltipNode); } }, 150); // 与CSS transition时长一致 }, isTouchscreen ? 16 : 100); } /** * 触摸设备:点击外部关闭弹窗 */ function setupClickOutsideHandler(tooltipData, tooltipNode, element) { const handler = function(e) { if (!tooltipNode.contains(e.target) && e.target !== element) { hideTooltip(tooltipData, tooltipNode); $(document).off("click touchstart", handler); // 移除事件避免泄漏 if (e.type === "touchstart") e.preventDefault(); // 防点击穿透 } }; $(document).on("click touchstart", handler); } /** * 触发弹窗显示 */ function triggerTooltip(element, tooltipData) { if (!tooltipData.originalTitle.trim()) return; // 创建或更新弹窗 if (!tooltipData.tooltipNode) { tooltipData.tooltipNode = createTooltipNode(tooltipData.originalTitle); } else { const $contentContainer = $(tooltipData.tooltipNode).find("li:first-child > div"); $contentContainer.replaceWith(createContentElement(tooltipData.originalTitle)); } // 定位并显示 positionTooltip(element, tooltipData.tooltipNode); showTooltip(tooltipData, tooltipData.tooltipNode); // 触摸设备绑定外部点击关闭 if (isTouchscreen) { setupClickOutsideHandler(tooltipData, tooltipData.tooltipNode, element); } } /*===== 事件委托:支持动态元素 =====*/ if (isTouchscreen) { // 触摸设备:点击触发 $bodyContent.on("click", ".inline-unihan", function(e) { e.preventDefault(); const element = this; const tooltipData = initElementData(element); // 切换显示/隐藏状态 if (tooltipData.tooltipNode && bodyContent.contains(tooltipData.tooltipNode)) { hideTooltip(tooltipData, tooltipData.tooltipNode); } else { triggerTooltip(element, tooltipData); } }); } else { // 非触摸设备:鼠标悬停触发 $bodyContent.on("mouseenter", ".inline-unihan", function() { const element = this; const tooltipData = initElementData(element); tooltipData.showTimer = setTimeout(() => { triggerTooltip(element, tooltipData); }, hoverDelay); }).on("mouseleave", ".inline-unihan", function() { const element = this; const tooltipData = initElementData(element); if (tooltipData.tooltipNode) { hideTooltip(tooltipData, tooltipData.tooltipNode); } }); } /*===== 窗口滚动时重新定位弹窗 =====*/ $(window).on("scroll", function() { $(".inline-unihan").each(function() { const tooltipData = $(this).data("tooltipData"); if (tooltipData && tooltipData.tooltipNode && bodyContent.contains(tooltipData.tooltipNode)) { positionTooltip(this, tooltipData.tooltipNode); } }); }); })(jQuery, mediaWiki);
返回
MediaWiki:Gadget-UnihanTooltips.js
。