-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcontent.js
More file actions
124 lines (94 loc) · 3.08 KB
/
content.js
File metadata and controls
124 lines (94 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
let debounceTimer = null;
let explorers = [];
// Load JSON once on page load
fetch(chrome.runtime.getURL('explorers.json'))
.then(res => res.json())
.then(data => explorers = data)
.catch(err => console.error("Failed to load explorers.json", err));
function buildTooltipLinks(text) {
if (!explorers.length) return '';
const isAddress = isSolanaAddress(text);
const isSignature = isSolanaSignature(text);
if (!isAddress && !isSignature) return '';
return explorers.map(explorer => {
if (isAddress ? explorer.accountUrl === "" : explorer.txUrl === "")
return
const href = isAddress
? explorer.accountUrl.replace('{address}', text)
: explorer.txUrl.replace('{signature}', text);
console.log("Getting icon", explorer)
const iconUrl = chrome.runtime.getURL(explorer.icon);
return `
<a href="${href}" target="_blank">
<img class="tooltip-img-sbgg" title="${explorer.name}" alt="${explorer.name}" src="${iconUrl}" />
</a>`;
}).join('\n');
}
function isSolanaAddress(text) {
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(text);
}
function isSolanaSignature(text) {
return /^[1-9A-HJ-NP-Za-km-z]{80,88}$/.test(text);
}
function getSelectionText() {
const selection = window.getSelection();
if (!selection || selection.rangeCount === 0) return null;
const text = selection.toString().trim();
if (!text) return null;
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect();
// Only show for visible selections (not collapsed or in invisible elements)
if (rect.width === 0 && rect.height === 0) return null;
// Ignore selections in form elements
const anchorNode = selection.anchorNode;
if (anchorNode) {
const parentEl = anchorNode.nodeType === 3 ? anchorNode.parentElement : anchorNode;
if (parentEl && ['INPUT', 'TEXTAREA'].includes(parentEl.tagName)) return null;
}
return {text, rect};
}
function createTooltip(text, rect) {
removeTooltip();
const tooltip = document.createElement('div');
tooltip.className = 'solana-tooltip-sbggg';
tooltip.innerHTML = buildTooltipLinks(text);
tooltip.style.left = `${window.scrollX + rect.left + 10}px`;
tooltip.style.top = `${window.scrollY + rect.bottom + 10}px`;
document.body.appendChild(tooltip);
}
function removeTooltip() {
document.querySelectorAll('.solana-tooltip-sbggg').forEach(el => el.remove());
}
let isDragging = false;
let latestSelection = null;
// Track drag
document.addEventListener('mousedown', () => {
isDragging = false;
});
document.addEventListener('mousemove', () => {
isDragging = true;
});
document.addEventListener('selectionchange', () => {
if (debounceTimer) clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
const selection = getSelectionText();
if (!selection) {
removeTooltip();
return;
}
const {text, rect} = selection;
if (isSolanaAddress(text) || isSolanaSignature(text)) {
createTooltip(text, rect);
}
}, 100);
});
document.addEventListener('click', (e) => {
if (isDragging) {
// Reset and ignore drag click
isDragging = false;
return;
}
if (!e.target.closest('.solana-tooltip')) {
removeTooltip();
}
});