const reportID = window.location.pathname.split("/").pop();
const clipBtn = document.getElementById('clip-btn');
const viewer = document.getElementById('document-viewer');
window.activeTextarea = null;
document.addEventListener('focusin', function(e) {
if (e.target && e.target.classList.contains('draft-desc')) {
window.activeTextarea = e.target;
}
});
viewer.addEventListener('mouseup', function(e) {
let selection = window.getSelection();
let text = selection.toString().trim();
if (text.length > 5) {
clipBtn.style.top = `${e.pageY - 50}px`;
clipBtn.style.left = `${e.pageX - 60}px`;
clipBtn.style.display = 'block';
clipBtn.onclick = async () => {
await saveNewDraft(text);
clipBtn.style.display = 'none';
selection.removeAllRanges();
};
} else {
clipBtn.style.display = 'none';
}
});
document.addEventListener('mousedown', (e) => {
if (e.target !== clipBtn && !viewer.contains(e.target)) {
clipBtn.style.display = 'none';
}
});
viewer.addEventListener('click', async function(e) {
if (e.target.tagName === 'IMG' && e.target.classList.contains('pentest-img')) {
const originalBorder = e.target.style.border;
e.target.style.transition = "border 0.2s, transform 0.2s";
e.target.style.border = "4px solid #f59e0b";
e.target.style.transform = "scale(0.98)";
try {
const uploadRes = await fetch('/api/images/upload', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ image_data: e.target.src })
});
if (!uploadRes.ok) throw new Error("Failed to upload image");
const data = await uploadRes.json();
const markdownImage = ``;
if (window.activeTextarea) {
const start = window.activeTextarea.selectionStart;
const end = window.activeTextarea.selectionEnd;
const text = window.activeTextarea.value;
window.activeTextarea.value = text.substring(0, start) + `\n${markdownImage}\n` + text.substring(end);
const draftId = window.activeTextarea.getAttribute('data-id');
updateLivePreview(draftId);
updateDraftField(draftId);
} else {
if (confirm("📸 Extract this screenshot into a BRAND NEW finding?\n\n(Tip: To add it to an existing finding, just click inside its Description box first!)")) {
await saveNewDraft(markdownImage);
}
}
e.target.style.border = "4px solid #10b981";
setTimeout(() => {
e.target.style.border = originalBorder;
e.target.style.transform = "scale(1)";
}, 800);
} catch (err) {
console.error(err);
e.target.style.border = "4px solid #ef4444";
alert("Error extracting image: " + err.message);
}
}
});
async function saveNewDraft(text) {
try {
const res = await fetch(`/api/drafts/report/${reportID}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ description: text })
});
if (res.ok) loadDrafts();
else alert("Failed to save draft: " + await res.text());
} catch (err) {
alert("Network error saving draft.");
}
}
window.updateDraftField = function(id) {
const card = document.querySelector(`.draft-card[data-id="${id}"]`);
if (!card) return;
const payload = {
title: card.querySelector('.draft-title').value,
asset_identifier: card.querySelector('.draft-asset').value,
severity: card.querySelector('.draft-severity').value,
description: card.querySelector('.draft-desc').value,
recommended_remediation: card.querySelector('.draft-remediation').value
};
fetch(`/api/drafts/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
}).catch(e => console.error("Auto-save failed", e));
}
window.renderMarkdown = function(text) {
if (!text) return "";
let html = text.replace(/!\[.*?\]\((.*?)\)/g, '
');
return html;
}
window.updateLivePreview = function(id) {
const card = document.querySelector(`.draft-card[data-id="${id}"]`);
if (!card) return;
const desc = card.querySelector('.draft-desc').value;
const preview = document.getElementById(`preview-${id}`);
if (desc.includes('![')) {
preview.style.display = 'block';
preview.innerHTML = renderMarkdown(desc);
} else {
preview.style.display = 'none';
}
}
async function loadDrafts() {
try {
const res = await fetch(`/api/drafts/report/${reportID}`);
if (!res.ok) return;
const drafts = await res.json();
const list = document.getElementById('draft-list');
if (!drafts || drafts.length === 0) {
list.innerHTML = `