Jegged-Tooltips

Adds tooltips to Jegged game gudies.

目前为 2025-03-26 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Jegged-Tooltips
  3. // @description Adds tooltips to Jegged game gudies.
  4. // @version 1.3
  5. // @license GPL-3.0-or-later
  6. // @include http://jegged.com/*
  7. // @include https://jegged.com/*
  8. // @run-at document-end
  9. // @namespace https://gf.qytechs.cn/users/115055
  10. // ==/UserScript==
  11.  
  12. let HOLD_TOOLTIP = false;
  13.  
  14. function showCardTooltip(card, elem, x, y) {
  15. removeCardTooltip();
  16. let tooltip = document.createElement("div");
  17. const margin = 10;
  18. const maxWidth = 650;
  19. let left = x;
  20. let top = y + window.scrollY;
  21. tooltip.id = "JeggedTooltip";
  22. tooltip.style.position = "absolute";
  23. tooltip.style.zIndex = 500;
  24.  
  25. tooltip.style.maxWidth = `${maxWidth}px`;
  26. tooltip.style.marginTop = `${margin}px`;
  27. tooltip.style.marginBottom = `${margin}px`;
  28. tooltip.style.marginRight = `${margin}px`;
  29. tooltip.style.marginLeft = `${margin}px`;
  30. card.style.marginTop = 0;
  31. card.style.marginBottom = 0;
  32. tooltip.append(card);
  33. document.body.append(tooltip);
  34. const elemRect = elem.getBoundingClientRect();
  35. const tooltipRect = tooltip.getBoundingClientRect();
  36. let headerHeight;
  37. const headerElem = document.getElementById("header");
  38. if (headerElem !== null) {
  39. headerHeight = headerElem.getBoundingClientRect().height;
  40. } else {
  41. headerHeight = 0;
  42. }
  43. // if destination position goes beyond viewport width, clamp position
  44. // within viewport or at 0
  45. if (x + tooltipRect.width + (margin*2) > window.innerWidth) {
  46. left = Math.max(window.innerWidth - tooltipRect.width - (margin*2), 0)
  47. }
  48.  
  49. // never cover target element with tooltip
  50. if (y < elemRect.top + elemRect.height + window.scrollY) {
  51. top = elemRect.top + elemRect.height + window.scrollY;
  52. }
  53. tooltip.style.left = `${left}px`;
  54. tooltip.style.top = `${top}px`;
  55. // if destination position goes beyond viewport height,
  56. // and tooltip fits above elem, display above elem
  57. if (top + tooltipRect.height + (margin*2) > window.scrollY + window.innerHeight) {
  58. if (elemRect.top - tooltipRect.height - (margin*2) - headerHeight >= 0) {
  59. top = window.scrollY + elemRect.top - tooltipRect.height - (margin*2);
  60. }
  61. }
  62. tooltip.style.left = `${left}px`;
  63. tooltip.style.top = `${top}px`;
  64. }
  65.  
  66. function removeCardTooltip() {
  67. const tooltip = document.getElementById("JeggedTooltip");
  68. if (tooltip) {
  69. tooltip.remove();
  70. }
  71. }
  72.  
  73. async function onMouseEnterLink(event) {
  74. const href = event.target.href;
  75. const url = URL.parse(href);
  76. if (url.origin !== window.location.origin) {
  77. // only follow same-origin links
  78. return;
  79. }
  80. if (url.hash === "") {
  81. // only follow anchor links
  82. return;
  83. }
  84. let x = event.x;
  85. let y = event.y;
  86. const onMouseMove = (e) => {
  87. x = e.x;
  88. y = e.y;
  89. }
  90. // keep latest cursor position for when tooltip content is ready
  91. document.addEventListener("mousemove", onMouseMove);
  92. try {
  93. const r = await fetch(url)
  94. if (!r.ok) {
  95. throw new Error(`Response status: ${r.status}`);
  96. }
  97.  
  98. const text = await r.text();
  99.  
  100. const parser = new DOMParser();
  101. const page = parser.parseFromString(text, "text/html");
  102.  
  103. const destination = page.getElementById(url.hash.slice(1));
  104. if (destination === null) {
  105. throw new Error(`Destination anchor not found on linked page.`)
  106. }
  107.  
  108. let card;
  109. if (destination.closest(".alert") !== null) {
  110. // if destination belongs to a card-style alert, use this
  111. card = destination.closest(".alert");
  112. } else if (destination.closest("tr") !== null) {
  113. // if destination belongs to a table, use nearest row
  114. card = document.createElement("div");
  115. card.innerHTML = destination.closest("tr").innerHTML;
  116. card.classList = "alert alert-secondary";
  117. } else {
  118. // element does not have associated card, do not display tooltip
  119. return;
  120. };
  121. showCardTooltip(card, event.target, x, y);
  122. } finally {
  123. document.removeEventListener("mousemove", onMouseMove);
  124. }
  125. }
  126.  
  127. function onMouseLeaveLink() {
  128. if (HOLD_TOOLTIP === false) {
  129. removeCardTooltip();
  130. }
  131. }
  132.  
  133. function onKeyDown(e) {
  134. if (e.key === "Shift") {
  135. HOLD_TOOLTIP = !HOLD_TOOLTIP;
  136. if (!HOLD_TOOLTIP) {
  137. removeCardTooltip();
  138. }
  139. } else if (e.key === "Escape") {
  140. removeCardTooltip();
  141. }
  142. }
  143.  
  144. function onScroll(e) {
  145. if (!HOLD_TOOLTIP) {
  146. removeCardTooltip();
  147. }
  148. }
  149.  
  150. function addEventListenersToLinks() {
  151. const links = document.getElementsByTagName("a");
  152. for (const l of links) {
  153. l.addEventListener("mouseenter", onMouseEnterLink);
  154. l.addEventListener("mouseleave", onMouseLeaveLink);
  155. }
  156. document.addEventListener("keydown", onKeyDown);
  157. document.addEventListener("scroll", onScroll);
  158. }
  159.  
  160. (() => {
  161. addEventListenersToLinks();
  162. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址