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.0
  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.  
  24. tooltip.style.maxWidth = `${maxWidth}px`;
  25. tooltip.style.marginTop = `${margin}px`;
  26. tooltip.style.marginBottom = `${margin}px`;
  27. tooltip.style.marginRight = `${margin}px`;
  28. tooltip.style.marginLeft = `${margin}px`;
  29. card.style.marginTop = 0;
  30. card.style.marginBottom = 0;
  31. tooltip.append(card);
  32. document.body.append(tooltip);
  33. const elemRect = elem.getBoundingClientRect();
  34. const tooltipRect = tooltip.getBoundingClientRect();
  35. let headerHeight;
  36. const headerElem = document.getElementById("header");
  37. if (headerElem !== null) {
  38. headerHeight = headerElem.getBoundingClientRect().height;
  39. } else {
  40. headerHeight = 0;
  41. }
  42. // if destination position goes beyond viewport width, clamp position
  43. // within viewport or at 0
  44. if (x + tooltipRect.width + (margin*2) > window.innerWidth) {
  45. left = Math.max(window.innerWidth - tooltipRect.width - (margin*2), 0)
  46. }
  47.  
  48. // never cover target element with tooltip
  49. if (y < elemRect.top + elemRect.height + window.scrollY) {
  50. top = elemRect.top + elemRect.height + window.scrollY;
  51. }
  52. tooltip.style.left = `${left}px`;
  53. tooltip.style.top = `${top}px`;
  54. // if destination position goes beyond viewport height,
  55. // and tooltip fits above elem, display above elem
  56. if (top + tooltipRect.height + (margin*2) > window.scrollY + window.innerHeight) {
  57. if (elemRect.top - tooltipRect.height - (margin*2) - headerHeight >= 0) {
  58. top = window.scrollY + elemRect.top - tooltipRect.height - (margin*2);
  59. }
  60. }
  61. tooltip.style.left = `${left}px`;
  62. tooltip.style.top = `${top}px`;
  63. }
  64.  
  65. function removeCardTooltip() {
  66. const tooltip = document.getElementById("JeggedTooltip");
  67. if (tooltip) {
  68. tooltip.remove();
  69. }
  70. }
  71.  
  72. async function onMouseEnterLink(event) {
  73. const href = event.target.href;
  74. const url = URL.parse(href);
  75. if (url.origin !== window.location.origin) {
  76. // only follow same-origin links
  77. return;
  78. }
  79. if (url.hash === "") {
  80. // only follow anchor links
  81. return;
  82. }
  83. let x = event.x;
  84. let y = event.y;
  85. const onMouseMove = (e) => {
  86. x = e.x;
  87. y = e.y;
  88. }
  89. document.addEventListener("mousemove", onMouseMove);
  90. try {
  91. const r = await fetch(url)
  92. if (!r.ok) {
  93. throw new Error(`Response status: ${r.status}`);
  94. }
  95.  
  96. const text = await r.text();
  97.  
  98. const parser = new DOMParser();
  99. const page = parser.parseFromString(text, "text/html");
  100.  
  101. const destination = page.getElementById(url.hash.slice(1));
  102. if (destination === null) {
  103. throw new Error(`Destination anchor not found on linked page.`)
  104. }
  105.  
  106. let card;
  107. if (destination.closest(".alert") !== null) {
  108. // if destination belongs to a card-style alert, use this
  109. card = destination.closest(".alert");
  110. } else if (destination.closest("tr") !== null) {
  111. // if destination belongs to a table, use nearest row
  112. card = document.createElement("div");
  113. card.innerHTML = destination.closest("tr").innerHTML;
  114. card.classList = "alert alert-secondary";
  115. } else {
  116. // element does not have associated card, do not display tooltip
  117. return;
  118. };
  119. showCardTooltip(card, event.target, x, y);
  120. } finally {
  121. document.removeEventListener("mousemove", onMouseMove);
  122. }
  123. }
  124.  
  125. function onMouseLeaveLink() {
  126. if (HOLD_TOOLTIP === false) {
  127. removeCardTooltip();
  128. }
  129. }
  130.  
  131. function onKeyDown(e) {
  132. if (e.key === "Shift") {
  133. HOLD_TOOLTIP = !HOLD_TOOLTIP;
  134. if (!HOLD_TOOLTIP) {
  135. removeCardTooltip();
  136. }
  137. } else if (e.key === "Escape") {
  138. removeCardTooltip();
  139. }
  140. }
  141.  
  142. function addEventListenersToLinks() {
  143. const links = document.getElementsByTagName("a");
  144. for (const l of links) {
  145. console.log(l);
  146. l.addEventListener("mouseenter", onMouseEnterLink);
  147. l.addEventListener("mouseleave", onMouseLeaveLink);
  148. }
  149. document.addEventListener("keydown", onKeyDown);
  150. }
  151.  
  152. (() => {
  153. addEventListenersToLinks();
  154. })();

QingJ © 2025

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