-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
113 lines (98 loc) · 4.02 KB
/
app.js
File metadata and controls
113 lines (98 loc) · 4.02 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
// IMPORTANT: Replace with your actual deployed serverless function URL
const API_BASE_URL = 'https://your-vercel-project-name.vercel.app/api';
const urlInput = document.getElementById('urlInput');
const fetchBtn = document.getElementById('fetchBtn');
const monitorBtn = document.getElementById('monitorBtn');
const previewContent = document.getElementById('preview-content');
const selectorDisplay = document.getElementById('selector-display');
let currentSelector = null;
let lastHighlighted = null;
// Fetches the page HTML from our proxy to get around CORS/X-Frame-Options
fetchBtn.addEventListener('click', async () => {
const url = urlInput.value;
if (!url) {
alert('Enter a URL first, comrade.');
return;
}
previewContent.innerHTML = '<h2>Fetching page... please wait.</h2>';
try {
const response = await fetch(`${API_BASE_URL}/fetch?url=${encodeURIComponent(url)}`);
const { html } = await response.json();
// Sanitize and inject HTML
const doc = new DOMParser().parseFromString(html, 'text/html');
// Re-base relative links to make them work from our page
const base = document.createElement('base');
base.href = url;
doc.head.prepend(base);
previewContent.innerHTML = new XMLSerializer().serializeToString(doc);
} catch (err) {
previewContent.innerHTML = `<h2>Error fetching page: ${err.message}</h2>`;
}
});
// Interactive element selection logic
document.getElementById('preview-overlay').addEventListener('mousemove', (e) => {
// We get the element from the "real" content div behind the overlay
const x = e.clientX - previewContent.getBoundingClientRect().left;
const y = e.clientY - previewContent.getBoundingClientRect().top + previewContent.scrollTop;
// Temporarily hide the overlay to get the element underneath
e.target.style.display = 'none';
const element = document.elementFromPoint(x, y);
e.target.style.display = 'block';
if (element && element !== lastHighlighted) {
if(lastHighlighted) lastHighlighted.classList.remove('highlight-element-on-hover');
element.classList.add('highlight-element-on-hover');
lastHighlighted = element;
}
});
document.getElementById('preview-overlay').addEventListener('click', (e) => {
if(lastHighlighted) {
currentSelector = getCssSelector(lastHighlighted);
selectorDisplay.textContent = currentSelector;
alert(`Selector Captured: ${currentSelector}`);
}
});
monitorBtn.addEventListener('click', async () => {
const url = urlInput.value;
if(!url || !currentSelector) {
alert('You must fetch a page and select an element first.');
return;
}
const webhook = prompt("Enter your Discord Webhook URL for notifications:");
if (!webhook) {
alert("Monitoring aborted. A webhook is required for alerts.");
return;
}
try {
const response = await fetch(`${API_BASE_URL}/start-monitoring`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url, selector: currentSelector, webhookUrl: webhook })
});
const result = await response.json();
alert(result.message);
} catch(err) {
alert(`Error: ${err.message}`);
}
});
// Function to generate a unique CSS selector for an element
function getCssSelector(el) {
if (!(el instanceof Element)) return;
const path = [];
while (el.nodeType === Node.ELEMENT_NODE) {
let selector = el.nodeName.toLowerCase();
if (el.id) {
selector += '#' + el.id;
path.unshift(selector);
break;
} else {
let sib = el, nth = 1;
while ((sib = sib.previousElementSibling)) {
if (sib.nodeName.toLowerCase() === selector) nth++;
}
if (nth !== 1) selector += `:nth-of-type(${nth})`;
}
path.unshift(selector);
el = el.parentNode;
}
return path.join(' > ');
}