« get me outta code hell

client: reposition tooltip nicely, when showing info column - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2024-06-18 14:22:48 -0300
committer(quasar) nebula <qznebula@protonmail.com>2024-06-18 22:56:13 -0300
commit77ce1001a972bb3635f734c96324766c0c4ecd94 (patch)
tree795c650482802ea6419ee9d0ce6dc0a3bc004c92 /src
parent1c2cb74a4ee266204f04be77a2add72ba98d627c (diff)
client: reposition tooltip nicely, when showing info column
Diffstat (limited to 'src')
-rw-r--r--src/static/js/client.js77
1 files changed, 53 insertions, 24 deletions
diff --git a/src/static/js/client.js b/src/static/js/client.js
index 98418a31..83459932 100644
--- a/src/static/js/client.js
+++ b/src/static/js/client.js
@@ -1271,6 +1271,11 @@ const hoverableTooltipInfo = initInfo('hoverableTooltipInfo', {
     // from causing the current tooltip to be hidden.
     currentTouchIdentifiers: new Set(),
     touchIdentifiersBanishedByScrolling: new Set(),
+
+    // This is a two-item array that tracks the direction we've already
+    // dynamically placed the current tooltip. If we *reposition* the tooltip
+    // (because its dimensions changed), we'll try to follow this anchor first.
+    dynamicTooltipAnchorDirection: null,
   },
 
   event: {
@@ -1731,6 +1736,8 @@ function hideCurrentlyShownTooltip(intendingToReplace = false) {
   state.currentlyShownTooltip = null;
   state.currentlyActiveHoverable = null;
 
+  state.dynamicTooltipAnchorDirection = null;
+
   // Set this for one tick of the event cycle.
   state.tooltipWasJustHidden = true;
   setTimeout(() => {
@@ -1792,10 +1799,23 @@ function peekTooltipClientRect(tooltip) {
   }
 }
 
+function repositionCurrentTooltip() {
+  const {state} = hoverableTooltipInfo;
+  const {currentlyActiveHoverable} = state;
+
+  if (!currentlyActiveHoverable) {
+    throw new Error(`No hoverable active to reposition tooltip from`);
+  }
+
+  positionTooltipFromHoverableWithBrains(currentlyActiveHoverable);
+}
+
 function positionTooltipFromHoverableWithBrains(hoverable) {
   const {state} = hoverableTooltipInfo;
   const {tooltip} = state.registeredHoverables.get(hoverable);
 
+  const anchorDirection = state.dynamicTooltipAnchorDirection;
+
   // Reset before doing anything else. We're going to adapt to
   // its natural placement, adjusted by CSS, which otherwise
   // could be obscured by a placement we've previously provided.
@@ -1817,35 +1837,42 @@ function positionTooltipFromHoverableWithBrains(hoverable) {
     return;
   }
 
-  let selectedRect = null;
-  for (let i = 0; i < numBaselineRects; i++) {
-    selectedRect = opportunities.right.down[i];
-    if (selectedRect) break;
-
-    selectedRect = opportunities.left.down[i];
-    if (selectedRect) break;
-
-    selectedRect = opportunities.right.up[i];
-    if (selectedRect) break;
-
-    selectedRect = opportunities.left.up[i];
-    if (selectedRect) break;
-
-    selectedRect = opportunities.down.right[i];
-    if (selectedRect) break;
+  const tryDirection = (dir1, dir2, i) => {
+    selectedRect = opportunities[dir1][dir2][i];
+    return !!selectedRect;
+  };
 
-    selectedRect = opportunities.down.left[i];
-    if (selectedRect) break;
+  let selectedRect = null;
+  selectRect: {
+    if (anchorDirection) {
+      for (let i = 0; i < numBaselineRects; i++) {
+        if (tryDirection(...anchorDirection, i)) {
+          break selectRect;
+        }
+      }
+    }
 
-    selectedRect = opportunities.up.right[i];
-    if (selectedRect) break;
+    for (let i = 0; i < numBaselineRects; i++) {
+      for (const [dir1, dir2] of [
+        ['right', 'down'],
+        ['left', 'down'],
+        ['right', 'up'],
+        ['left', 'up'],
+        ['down', 'right'],
+        ['down', 'left'],
+        ['up', 'right'],
+        ['up', 'left'],
+      ]) {
+        if (tryDirection(dir1, dir2, i)) {
+          state.dynamicTooltipAnchorDirection = [dir1, dir2];
+          break selectRect;
+        }
+      }
+    }
 
-    selectedRect = opportunities.up.left[i];
-    if (selectedRect) break;
+    selectedRect = baselineRect;
   }
 
-  selectedRect ??= baselineRect;
-
   positionTooltip(tooltip, selectedRect.x, selectedRect.y);
 }
 
@@ -3577,6 +3604,8 @@ function showArtistExternalLinkTooltipInfo() {
   for (const tooltip of info.tooltips) {
     tooltip.classList.add('show-info');
   }
+
+  repositionCurrentTooltip();
 }
 
 function hideArtistExternalLinkTooltipInfo() {