-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
89 lines (80 loc) · 3.3 KB
/
Copy pathapp.js
File metadata and controls
89 lines (80 loc) · 3.3 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
const root = document.documentElement;
const themeButton = document.querySelector("[data-theme-toggle]");
const navToggle = document.querySelector("[data-nav-toggle]");
const nav = document.querySelector(".nav-links");
const savedTheme = localStorage.getItem("010-editor-theme");
if (savedTheme === "dark") root.dataset.theme = "dark";
if (themeButton) {
const updateThemeLabel = () => {
const dark = root.dataset.theme === "dark";
themeButton.setAttribute("aria-label", dark ? "Switch to light theme" : "Switch to dark theme");
themeButton.textContent = dark ? "☀" : "☾";
};
updateThemeLabel();
themeButton.addEventListener("click", () => {
const dark = root.dataset.theme === "dark";
if (dark) delete root.dataset.theme;
else root.dataset.theme = "dark";
localStorage.setItem("010-editor-theme", dark ? "light" : "dark");
updateThemeLabel();
});
}
if (navToggle && nav) {
navToggle.addEventListener("click", () => {
const open = nav.classList.toggle("open");
navToggle.setAttribute("aria-expanded", String(open));
});
nav.querySelectorAll("a").forEach(link => {
link.addEventListener("click", () => {
nav.classList.remove("open");
navToggle.setAttribute("aria-expanded", "false");
});
});
}
const hexInput = document.querySelector("#hex-input");
const hexOutput = document.querySelector("#hex-output");
const textOutput = document.querySelector("#text-output");
const endianButtons = document.querySelectorAll("[data-endian]");
function cleanHex(value) {
return value.replace(/[^0-9a-f]/gi, "").match(/.{1,2}/g)?.join(" ") ?? "";
}
function renderBytes() {
if (!hexInput || !hexOutput || !textOutput) return;
const normalized = cleanHex(hexInput.value);
const parts = normalized ? normalized.split(" ") : [];
const bytes = parts.map(part => Number.parseInt(part, 16)).filter(Number.isFinite);
hexOutput.textContent = bytes.map(byte => byte.toString(16).padStart(2, "0").toUpperCase()).join(" ");
textOutput.textContent = bytes.map(byte => byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : "·").join("");
hexInput.value = normalized;
}
if (hexInput) {
hexInput.addEventListener("input", renderBytes);
renderBytes();
}
endianButtons.forEach(button => {
button.addEventListener("click", () => {
endianButtons.forEach(item => item.setAttribute("aria-pressed", "false"));
button.setAttribute("aria-pressed", "true");
const bytes = cleanHex(hexInput.value).split(" ").filter(Boolean);
if (bytes.length < 4) return;
const group = bytes.slice(0, 4);
const reordered = button.dataset.endian === "little" ? [...group].reverse() : group;
const remaining = bytes.slice(4);
hexInput.value = [...reordered, ...remaining].join(" ");
renderBytes();
});
});
document.querySelectorAll("[data-copy]").forEach(button => {
button.addEventListener("click", async () => {
const target = document.querySelector(button.dataset.copy);
if (!target) return;
try {
await navigator.clipboard.writeText(target.textContent);
const original = button.textContent;
button.textContent = "Copied";
setTimeout(() => button.textContent = original, 1200);
} catch {
button.textContent = "Select to copy";
}
});
});