Skip to content

Add linkText to AlphabetHints #4689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 94 additions & 11 deletions content_scripts/link_hints.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,8 @@ class LinkHintsMode {
this.hintMode = null;
// A count of the number of Tab presses since the last non-Tab keyboard event.
this.tabCount = 0;
// Track whether we've already applied overlap offsets for link hints
this.overlapOffsetsApplied = false;

if (hintDescriptors.length === 0) {
HUD.show("No links to select.", 2000);
Expand Down Expand Up @@ -425,6 +427,12 @@ class LinkHintsMode {
this.containerEl.appendChild(el);
}

// Only apply overlap offsets to link hints once during initial setup
if (!this.overlapOffsetsApplied) {
this.applyOverlapOffsets();
this.overlapOffsetsApplied = true;
}

// TODO(philc): 2024-03-27 Remove this hasPopoverSupport check once Firefox has popover support.
// Also move this CSS into vimium.css.
const hasPopoverSupport = this.containerEl.showPopover != null;
Expand Down Expand Up @@ -484,6 +492,13 @@ class LinkHintsMode {
// Note that Vimium's CSS is user-customizable. We're adding the "vimiumHintMarker" class here
// for users to customize. See further comments about this in vimium.css.
el.className = "vimium-reset internal-vimium-hint-marker vimiumHintMarker";
// Add scroll-hint-marker class for frames or scrollable areas in alphabet hints mode.
if (
(localHint.reason === "Frame." || localHint.reason === "Scroll.") &&
!Settings.get("filterLinkHints")
) {
el.classList.add("scroll-hint-marker");
}
Object.assign(marker, {
element: el,
localHint,
Expand All @@ -497,6 +512,68 @@ class LinkHintsMode {
});
}

// Add a new method to detect and handle overlapping markers
applyOverlapOffsets() {
const localMarkers = this.hintMarkers.filter(m => m.isLocalMarker() && m.element);

// Cache marker rectangles
localMarkers.forEach(marker => {
marker.markerRect = marker.element.getBoundingClientRect();
});

// Group overlapping markers into stacks
const stacks = this.groupOverlappingMarkers(localMarkers);

// Apply position offsets to overlapping markers
stacks.forEach(stack => {
if (stack.length > 1) {
stack.forEach((marker, index) => {
if (index > 0) {
const offset = index * 2;
const currentLeft = parseInt(marker.element.style.left) || 0;
const currentTop = parseInt(marker.element.style.top) || 0;

marker.element.style.left = (currentLeft + offset) + "px";
marker.element.style.top = (currentTop + offset) + "px";
}
});
}
});
}

// Helper to group overlapping markers
groupOverlappingMarkers(markers) {
const stacks = [];

for (const marker of markers) {
let assignedStack = null;

// Find stacks that overlap with this marker
const overlappingStacks = stacks.filter(stack =>
stack.some(otherMarker => Rect.intersects(marker.markerRect, otherMarker.markerRect))
);

if (overlappingStacks.length === 0) {
// No overlaps, create new stack
stacks.push([marker]);
} else if (overlappingStacks.length === 1) {
// Overlaps with one stack, add to it
overlappingStacks[0].push(marker);
} else {
// Overlaps with multiple stacks, merge them
const mergedStack = [marker, ...overlappingStacks.flat()];
// Remove old stacks and add merged stack
overlappingStacks.forEach(stack => {
const index = stacks.indexOf(stack);
if (index > -1) stacks.splice(index, 1);
});
stacks.push(mergedStack);
}
}

return stacks;
}

// Handles all keyboard events.
onKeyDownInMode(event) {
if (event.repeat) return;
Expand Down Expand Up @@ -808,18 +885,24 @@ class AlphabetHints {
this.hintKeystrokeQueue = [];
}

renderMarker(marker) {
let linkText = marker.linkText;
const caption = marker.hintString.toUpperCase()
+ (marker.localHint.showLinkText ? ": " + linkText : "");
marker.element.innerHTML = spanWrap(caption);
}

fillInMarkers(hintMarkers) {
const hintStrings = this.hintStrings(hintMarkers.length);
if (hintMarkers.length != hintStrings.length) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this safety check no longer needed?

// This can only happen if the user's linkHintCharacters setting is empty.
console.warn("Unable to generate link hint strings.");
} else {
for (let i = 0; i < hintMarkers.length; i++) {
const marker = hintMarkers[i];
marker.hintString = hintStrings[i];
if (marker.isLocalMarker()) {
marker.element.innerHTML = spanWrap(marker.hintString.toUpperCase());
}
}
let i = 0;
for (const marker of hintMarkers) {
marker.hintString = hintStrings[i++];
if (marker.isLocalMarker()) {
this.renderMarker(marker);
}
}
}
Expand Down Expand Up @@ -1202,13 +1285,13 @@ const LocalHints = {
break;
case "body":
isClickable ||= (element === document.body) && !windowIsFocused() &&
(globalThis.innerWidth > 3) && (globalThis.innerHeight > 3) &&
((document.body != null ? document.body.tagName.toLowerCase() : undefined) !==
"frameset")
(globalThis.innerWidth > 3) && (globalThis.innerHeight > 3) &&
((document.body != null ? document.body.tagName.toLowerCase() : undefined) !==
"frameset")
? (reason = "Frame.")
: undefined;
isClickable ||= (element === document.body) && windowIsFocused() &&
Scroller.isScrollableElement(element)
Scroller.isScrollableElement(element)
? (reason = "Scroll.")
: undefined;
break;
Expand Down
5 changes: 5 additions & 0 deletions content_scripts/vimium.css
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ div.internal-vimium-hint-marker {
z-index: 2147483647;
}

div.internal-vimium-hint-marker.scroll-hint-marker {
/* This class is used for marking scrollable areas or frames */
background: linear-gradient(to bottom, #ffb2b2 0%, #ff7a7a 100%);
}

div.internal-vimium-hint-marker span {
color: #302505;
font-family: Helvetica, Arial, sans-serif;
Expand Down