Add region selection and command generation features

This commit is contained in:
√(noham)²
2026-01-25 12:05:11 +01:00
parent ad9a07dafb
commit 3f54439ad8
4 changed files with 188 additions and 6 deletions

147
src.js
View File

@@ -1,5 +1,6 @@
let allRegions = [];
let currentSort = { column: null, direction: "asc" };
let selectedRegions = new Set();
// Dark Mode Toggle
function toggleDarkMode() {
@@ -95,6 +96,7 @@ function parseMemory() {
}
allRegions = regions;
selectedRegions.clear();
updateStats(regions);
document.getElementById("stats").classList.remove("hidden");
document.getElementById("stats").classList.add("grid");
@@ -189,7 +191,10 @@ function renderTable(regions) {
: "hover:bg-slate-50 dark:hover:bg-slate-700";
return `
<tr class="${rowClass} transition-colors border-b border-slate-100 dark:border-slate-700 last:border-0">
<tr class="${rowClass} transition-colors border-b border-slate-100 dark:border-slate-700 last:border-0" data-start="${r.startStr}" data-end="${r.endStr}">
<td class="px-6 py-3 whitespace-nowrap">
<input type="checkbox" class="row-checkbox rounded text-indigo-600 focus:ring-indigo-500 cursor-pointer" data-start="${r.startStr}" data-end="${r.endStr}" onchange="updateSelection()" ${selectedRegions.has(r.startStr) ? "checked" : ""}>
</td>
<td class="px-6 py-3 whitespace-nowrap font-mono text-xs text-slate-600 dark:text-slate-400 select-all">${r.startStr}</td>
<td class="px-6 py-3 whitespace-nowrap font-mono text-xs text-slate-600 dark:text-slate-400 select-all">${r.endStr}</td>
<td class="px-6 py-3 whitespace-nowrap text-sm text-slate-700 dark:text-slate-300 font-medium" title="${r.size.toString()} bytes">${formatBytes(r.size)}</td>
@@ -214,6 +219,9 @@ function renderTable(regions) {
remaining > 0
? `${dataset.length} rows shown (${remaining} hidden for performance)`
: `${dataset.length} rows`;
// Update select-all checkbox state
updateSelectAllCheckbox();
}
// --- Helpers & Utilities ---
@@ -249,7 +257,7 @@ function sortBy(column) {
// Update active header
const headers = document.querySelectorAll("th");
headers.forEach((th) => {
if (th.onclick.toString().includes(column)) {
if (th.onclick && th.onclick.toString().includes(column)) {
const icon = th.querySelector(".sort-icon");
icon.textContent = currentSort.direction === "asc" ? "▲" : "▼";
icon.classList.add("text-indigo-600");
@@ -260,6 +268,136 @@ function sortBy(column) {
applyFilters();
}
// --- Selection and Command Generation ---
function toggleSelectAll() {
const selectAllCheckbox = document.getElementById("select-all");
const checkboxes = document.querySelectorAll(".row-checkbox");
checkboxes.forEach((checkbox) => {
checkbox.checked = selectAllCheckbox.checked;
const start = checkbox.dataset.start;
const end = checkbox.dataset.end;
if (selectAllCheckbox.checked) {
selectedRegions.add(start);
} else {
selectedRegions.delete(start);
}
});
updateGenerateButton();
updateSelectedCount();
}
function updateSelection() {
const checkboxes = document.querySelectorAll(".row-checkbox");
checkboxes.forEach((checkbox) => {
const start = checkbox.dataset.start;
if (checkbox.checked) {
selectedRegions.add(start);
} else {
selectedRegions.delete(start);
}
});
updateSelectAllCheckbox();
updateGenerateButton();
updateSelectedCount();
}
function updateSelectAllCheckbox() {
const selectAllCheckbox = document.getElementById("select-all");
const checkboxes = document.querySelectorAll(".row-checkbox");
if (checkboxes.length === 0) {
selectAllCheckbox.checked = false;
selectAllCheckbox.indeterminate = false;
return;
}
const checkedCount = Array.from(checkboxes).filter((cb) => cb.checked).length;
if (checkedCount === 0) {
selectAllCheckbox.checked = false;
selectAllCheckbox.indeterminate = false;
} else if (checkedCount === checkboxes.length) {
selectAllCheckbox.checked = true;
selectAllCheckbox.indeterminate = false;
} else {
selectAllCheckbox.checked = false;
selectAllCheckbox.indeterminate = true;
}
}
function updateGenerateButton() {
const generateBtn = document.getElementById("generate-btn");
generateBtn.disabled = selectedRegions.size === 0;
}
function updateSelectedCount() {
const countSpan = document.getElementById("selected-count");
if (countSpan) {
countSpan.textContent = selectedRegions.size;
}
}
function generateCommands() {
if (selectedRegions.size === 0) return;
const commands = [];
// Get selected regions in order
const selectedRegionObjs = allRegions.filter((r) =>
selectedRegions.has(r.startStr),
);
selectedRegionObjs.forEach((region) => {
const startAddr = region.startStr;
const endAddr = region.endStr;
const command = `memory read --outfile /tmp/dump_${startAddr}_${endAddr}.bin --binary ${startAddr} ${endAddr}`;
commands.push(command);
});
const commandsText = document.getElementById("commands-text");
commandsText.textContent = commands.join("\n");
document.getElementById("command-output").classList.remove("hidden");
// Scroll to commands
document
.getElementById("command-output")
.scrollIntoView({ behavior: "smooth", block: "nearest" });
}
function copyCommands(event) {
const commandsText = document.getElementById("commands-text").textContent;
navigator.clipboard
.writeText(commandsText)
.then(() => {
// Visual feedback
const copyBtn = event.target.closest("button");
const originalText = copyBtn.innerHTML;
copyBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
Copied!
`;
setTimeout(() => {
copyBtn.innerHTML = originalText;
}, 2000);
})
.catch((err) => {
console.error("Failed to copy:", err);
alert("Failed to copy to clipboard");
});
}
function applyFilters() {
const addrFilter = document
.getElementById("addressFilter")
@@ -343,11 +481,12 @@ function applyFilters() {
function clearAll() {
document.getElementById("input").value = "";
document.getElementById("table-body").innerHTML =
`<tr><td colspan="6" class="py-12 text-center text-slate-400">Waiting for input...</td></tr>`;
`<tr><td colspan="7" class="py-12 text-center text-slate-400">Waiting for input...</td></tr>`;
document.getElementById("stats").classList.add("hidden");
document.getElementById("stats").classList.remove("grid");
document.getElementById("filter-section").classList.add("hidden");
document.getElementById("filter-section").classList.remove("flex");
document.getElementById("command-output").classList.add("hidden");
document.getElementById("footer-count").innerText = "0 rows";
// Reset filters
@@ -357,4 +496,6 @@ function clearAll() {
allRegions = [];
currentSort = { column: null, direction: "asc" };
selectedRegions.clear();
updateGenerateButton();
}