跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
分类索引
最近更改
随便看看
灵兰秘典
捐助本站
帮助
帮助
联系我们
关于本站
MediaWiki帮助
中医百科
搜索
搜索
外观
登录
个人工具
登录
查看“︁MediaWiki:Gadget-UnihanTooltips.js”︁的源代码
系统消息
讨论
English
阅读
查看源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
查看源代码
查看历史
清除缓存
常规
链入页面
相关更改
特殊页面
页面信息
Cargo数据
短URL
外观
移至侧栏
隐藏
←
MediaWiki:Gadget-UnihanTooltips.js
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
此页面为本wiki上的软件提供界面文本,并受到保护以防止滥用。 如欲修改所有wiki的翻译,请访问
translatewiki.net
上的MediaWiki本地化项目。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有访问者。
您可以查看和复制此页面的源代码。
/* 本小工具可以將[[Template:僻字]]的提示由原來的title提示改為元素式彈出提示,使觸控式裝置可以觀看有關提示 适配说明:兼容MediaWiki 1.43版本,弃用过时API,支持动态元素,优化触摸体验,修复布局抖动 */ // 显式传入jQuery和mediaWiki,避免$冲突 (function($, mw) { "use strict"; // 启用严格模式,减少语法错误 /*===== 初始化检查:控制工具是否加载(替换Cookie为本地存储) =====*/ // 获取URL参数"UTdontload"(0=清除不加载状态,数字=设置不加载状态) const dontLoadParam = mw.util.getParamValue("UTdontload"); // 处理参数:设置/清除"不加载"状态(使用mw.storage,1.43推荐) if (dontLoadParam !== null) { const paramVal = parseInt(dontLoadParam, 10); if (!isNaN(paramVal)) { // 参数为0:清除本地存储的不加载状态 if (paramVal === 0) { mw.storage.remove("UTdontload"); } else { // 参数为非0数字:设置不加载状态(永久有效,除非手动清除) 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; } // 获取内容容器(1.43推荐直接选择器获取,兼容性更好) const $bodyContent = $("#mw-content-text").length ? $("#mw-content-text") : $("body"); const bodyContent = $bodyContent[0]; // 转为原生DOM对象 // 设备类型检测(适配1.43触摸设备判断逻辑) const isTouchscreen = window.matchMedia("(hover: none), (pointer: coarse)").matches || mw.config.get("wgDisplayResolution") === "mobile" || "ontouchstart" in document.documentElement; const hoverDelay = isTouchscreen ? 0 : 200; // 悬停延迟:触摸设备无延迟 /*===== 工具函数:弹窗创建/更新/定位/控制 =====*/ /** * 初始化单个僻字元素的数据(存储到元素data中,避免全局污染) * @param {HTMLElement} element - .inline-unihan元素 * @returns {Object} 弹窗相关数据 */ function initElementData(element) { let tooltipData = $(element).data("tooltipData"); if (!tooltipData) { // 保存原始title,清空默认提示 const originalTitle = element.title || ""; element.title = ""; // 标记目标元素(用于CSS样式) $(element).addClass("UHTarget"); // 初始化弹窗数据(存储到元素data中) tooltipData = { originalTitle: originalTitle, tooltipNode: null, // 弹窗DOM节点 hideTimer: null, // 隐藏定时器 showTimer: null // 显示定时器 }; $(element).data("tooltipData", tooltipData); } return tooltipData; } /** * 创建/更新弹窗内容(支持多段落,适配原始title换行) * @param {string} originalTitle - 原始title文本 * @returns {HTMLElement} 内容容器DOM */ 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结构(包含内容区、设置图标、箭头) * @param {string} originalTitle - 原始title文本 * @returns {HTMLElement} 弹窗DOM节点 */ function createTooltipNode(originalTitle) { // 弹窗容器(ul标签,用于样式控制) const tooltipNode = document.createElement("ul"); tooltipNode.className = "unihantooltip"; // 内容区li(包含提示内容和设置图标) const $contentLi = $("<li>"); // 提示内容 const contentElement = createContentElement(originalTitle); // 设置图标(预留设置功能入口) const $settingsIcon = $("<div>") .addClass("UHsettings") .attr("title", "设置") .on("click", (e) => { e.stopPropagation(); // 阻止事件冒泡,避免关闭弹窗 // 可扩展设置逻辑:如弹窗样式、显示开关等 }); // 组装内容区 $contentLi.append(contentElement).append($settingsIcon); // 箭头li(用于指向目标元素) const $arrowLi = $("<li>"); // 组装弹窗 $(tooltipNode).append($contentLi).append($arrowLi); // 非触摸设备:绑定弹窗悬停事件 if (!isTouchscreen) { $(tooltipNode) .on("mouseenter", function() { const tooltipData = $(this).data("tooltipData"); showTooltip(tooltipData, this); }) .on("mouseleave", function() { const tooltipData = $(this).data("tooltipData"); hideTooltip(tooltipData, this); }); } return tooltipNode; } /** * 弹窗定位(精准对齐目标元素,避免超出视口,无布局抖动) * @param {HTMLElement} element - 目标僻字元素 * @param {HTMLElement} tooltipNode - 弹窗DOM节点 */ function positionTooltip(element, tooltipNode) { const $element = $(element); const $tooltip = $(tooltipNode); // 离线获取尺寸:避免布局抖动(visibility:hidden不触发重排) $tooltip.css({ visibility: "hidden", display: "block", position: "absolute" }).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 - 13; // 13px=CSS内边距补偿 } top = Math.max(viewport.top, Math.min(top, viewport.bottom - contentHeight)); /*===== 水平定位:居中对齐,避免超出左右边界 =====*/ let left = elementOffset.left + (elementWidth - tooltipWidth) / 2; // 左右留10px安全边距 left = Math.max(viewport.left + 10, Math.min(left, viewport.right - tooltipWidth - 10)); /*===== 箭头定位:精准指向目标元素中心 =====*/ const arrowOffset = elementOffset.left - left + elementWidth / 2 - 7; // 7px=箭头偏移补偿 $tooltip.find("li:last-child").css("margin-left", `${arrowOffset}px`); /*===== 应用定位并恢复显示状态 =====*/ $tooltip.css({ top: `${top}px`, left: `${left}px`, visibility: "visible", display: "" }); } /** * 显示弹窗(清除隐藏定时器,执行淡入动画) * @param {Object} tooltipData - 弹窗数据对象 * @param {HTMLElement} tooltipNode - 弹窗DOM节点 */ function showTooltip(tooltipData, tooltipNode) { // 确保弹窗已插入DOM if (!tooltipNode.parentNode || tooltipNode.parentNode.nodeType === 11) { bodyContent.appendChild(tooltipNode); } // 停止动画排队,淡入显示 $(tooltipNode).stop().animate({ opacity: 1 }, 100); // 清除隐藏定时器 if (tooltipData.hideTimer) { clearTimeout(tooltipData.hideTimer); tooltipData.hideTimer = null; } } /** * 隐藏弹窗(延迟执行,执行淡出动画后移除) * @param {Object} tooltipData - 弹窗数据对象 * @param {HTMLElement} tooltipNode - 弹窗DOM节点 */ function hideTooltip(tooltipData, tooltipNode) { // 清除显示定时器 if (tooltipData.showTimer) { clearTimeout(tooltipData.showTimer); tooltipData.showTimer = null; } // 延迟隐藏(避免误触) tooltipData.hideTimer = setTimeout(() => { // 淡出动画后移除弹窗 $(tooltipNode).animate({ opacity: 0 }, 100, () => { if (bodyContent.contains(tooltipNode)) { bodyContent.removeChild(tooltipNode); } }); }, isTouchscreen ? 16 : 100); } /** * 触摸设备:点击弹窗外区域关闭弹窗(防点击穿透) * @param {Object} tooltipData - 弹窗数据对象 * @param {HTMLElement} tooltipNode - 弹窗DOM节点 * @param {HTMLElement} element - 目标僻字元素 */ 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); // 阻止touchstart默认行为,防止点击穿透 if (e.type === "touchstart") { e.preventDefault(); } } }; // 绑定文档点击/触摸事件 $(document).on("click touchstart", handler); } /** * 触发弹窗显示(根据设备类型处理) * @param {HTMLElement} element - 目标僻字元素 * @param {Object} tooltipData - 弹窗数据对象 */ 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); } } /*===== 事件委托:支持动态加载的僻字元素(1.43关键优化) =====*/ // 触摸设备:绑定点击事件 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); } }); } })(jQuery, mediaWiki);
返回
MediaWiki:Gadget-UnihanTooltips.js
。