From eb04e071c37341bdc2796d27cd3d170f1afee518 Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Sat, 27 Sep 2025 23:32:40 +0200 Subject: [PATCH] ux improvements --- index.html | 412 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 290 insertions(+), 122 deletions(-) diff --git a/index.html b/index.html index 1837ada..2e54ee8 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,6 @@ + @@ -311,7 +312,7 @@ font-size: 0.8em; padding: 6px; } - + .calc-input input { font-size: 16px; padding: 10px; @@ -485,7 +486,7 @@ z-index: 1000; max-width: 400px; word-wrap: break-word; - box-shadow: 0 4px 8px rgba(0,0,0,0.3); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); font-family: 'Consolas', monospace; line-height: 1.4; } @@ -496,7 +497,7 @@ align-items: flex-start; gap: 5px; } - + .result-value { text-align: left; min-width: auto; @@ -568,16 +569,16 @@ .main-content { padding: 15px; } - + h1 { font-size: 1.8em; margin-bottom: 20px; } - + .section { padding: 15px; } - + .formula-box { padding: 12px; font-size: 0.85em; @@ -596,6 +597,7 @@ } +
@@ -623,11 +625,13 @@

Konstanten

- +
- +
@@ -713,7 +717,8 @@

Eingabeparameter

- +
@@ -721,23 +726,28 @@
- +
- +
- +
- +
- +
@@ -747,66 +757,89 @@

Berechnete Werte

- Beginn FAT-Bereich: + Beginn + FAT-Bereich:
- - +
Größe FAT-Bereich:
- - +
Ende FAT-Bereich:
- - +
- Größe Wurzelverzeichnis: + Beginn Wurzelverzeichnis: +
+ - + +
+
+
+ Größe + Wurzelverzeichnis:
- - +
Beginn Daten-Bereich:
- - +
- Größe Daten-Bereich: + Größe + Daten-Bereich:
- - +
- Größe eines Clusters: + Größe eines + Clusters:
- - +
Anzahl Cluster:
- - +
- Beginn Cluster: + Beginn Cluster:
- - +
@@ -815,15 +848,24 @@

Berechnungsformeln FAT12/16

-
Beginn FAT-Bereich = Anzahl reservierter Sektoren × Größe eines Sektors + Base Offset
-
Größe FAT-Bereich = Anzahl FATs × Größe einer FAT
-
Ende FAT-Bereich = Beginn FAT-Bereich + Größe FAT-Bereich
-
Größe Wurzelverzeichnis = Anzahl max. Wurzelverzeichnis-Einträge × 0x20
-
Beginn Daten-Bereich = Ende FAT-Bereich + Größe Wurzelverzeichnis
-
Größe Daten-Bereich = (Größe Partition in Sektoren × Größe eines Sektors) - (Beginn Daten-Bereich - Base Offset)
-
Größe eines Clusters = Größe eines Sektors × Größe eines Clusters in Sektoren
-
Anzahl Cluster = Größe Daten-Bereich ÷ Größe eines Clusters
-
Beginn Cluster = Beginn Daten-Bereich + (Cluster - 0x2) × Größe eines Clusters
+
Beginn FAT-Bereich = Anzahl reservierter + Sektoren × Größe eines Sektors + Base Offset
+
Größe FAT-Bereich = Anzahl FATs × Größe + einer FAT
+
Ende FAT-Bereich = Beginn FAT-Bereich + + Größe FAT-Bereich
+
Größe Wurzelverzeichnis = Anzahl max. + Wurzelverzeichnis-Einträge × 0x20
+
Beginn Daten-Bereich = Ende FAT-Bereich + + Größe Wurzelverzeichnis
+
Größe Daten-Bereich = (Größe Partition in + Sektoren × Größe eines Sektors) - (Beginn Daten-Bereich - Base Offset)
+
Größe eines Clusters = Größe eines Sektors + × Größe eines Clusters in Sektoren
+
Anzahl Cluster = Größe Daten-Bereich ÷ + Größe eines Clusters
+
Beginn Cluster = Beginn Daten-Bereich + + (Cluster - 0x2) × Größe eines Clusters
@@ -835,11 +877,13 @@

Konstanten

- +
- +
@@ -880,25 +924,32 @@ - +
- +
- - + + - +
- - + + @@ -925,7 +976,8 @@

Eingabeparameter

- +
@@ -933,23 +985,28 @@
- +
- +
- +
- +
- +
@@ -959,66 +1016,82 @@

Berechnete Werte

- Beginn FAT-Bereich: + Beginn + FAT-Bereich:
- - +
Größe FAT-Bereich:
- - +
Ende FAT-Bereich:
- - +
Beginn Daten-Bereich:
- - +
- Größe Daten-Bereich: + Größe + Daten-Bereich:
- - +
- Größe eines Clusters: + Größe eines + Clusters:
- - +
Anzahl Cluster:
- - +
- Beginn Cluster: + Beginn Cluster:
- - +
- Root Directory Position: + Root Directory + Position:
- - +
@@ -1027,15 +1100,24 @@

Berechnungsformeln FAT32

-
Beginn FAT-Bereich = Anzahl reservierter Sektoren × Größe eines Sektors + Base Offset
-
Größe FAT-Bereich = Anzahl FATs × Größe einer FAT
-
Ende FAT-Bereich = Beginn FAT-Bereich + Größe FAT-Bereich
-
Beginn Daten-Bereich = Ende FAT-Bereich (kein festes Root Directory)
-
Größe Daten-Bereich = (Größe Partition in Sektoren × Größe eines Sektors) - (Beginn Daten-Bereich - Base Offset)
-
Größe eines Clusters = Größe eines Sektors × Größe eines Clusters in Sektoren
-
Anzahl Cluster = Größe Daten-Bereich ÷ Größe eines Clusters
-
Beginn Cluster = Beginn Daten-Bereich + (Cluster - 0x2) × Größe eines Clusters
-
Root Directory Position = Beginn Daten-Bereich + (Root Directory Cluster - 0x2) × Größe eines Clusters
+
Beginn FAT-Bereich = Anzahl reservierter + Sektoren × Größe eines Sektors + Base Offset
+
Größe FAT-Bereich = Anzahl FATs × Größe + einer FAT
+
Ende FAT-Bereich = Beginn FAT-Bereich + + Größe FAT-Bereich
+
Beginn Daten-Bereich = Ende FAT-Bereich + (kein festes Root Directory)
+
Größe Daten-Bereich = (Größe Partition in + Sektoren × Größe eines Sektors) - (Beginn Daten-Bereich - Base Offset)
+
Größe eines Clusters = Größe eines Sektors + × Größe eines Clusters in Sektoren
+
Anzahl Cluster = Größe Daten-Bereich ÷ + Größe eines Clusters
+
Beginn Cluster = Beginn Daten-Bereich + + (Cluster - 0x2) × Größe eines Clusters
+
Root Directory Position = Beginn + Daten-Bereich + (Root Directory Cluster - 0x2) × Größe eines Clusters
@@ -1104,19 +1186,19 @@ const currentTab = tab || getCurrentTab(); const state = getCalculatorState(currentTab); const suffix = currentTab === 'fat32' ? '32' : ''; - + const inputElement = document.getElementById(`calcInput${suffix}`); const hexElement = document.getElementById(`hexValue${suffix}`); const decElement = document.getElementById(`decValue${suffix}`); const binElement = document.getElementById(`binValue${suffix}`); - + // Ensure value is within JavaScript's safe integer range const value = Math.max(0, Math.min(state.currentValue, Number.MAX_SAFE_INTEGER)); - + const hexStr = '0x' + value.toString(16).toUpperCase(); const decStr = value.toString(10); const binStr = '0b' + value.toString(2); - + inputElement.value = hexStr; hexElement.textContent = hexStr; decElement.textContent = decStr; @@ -1126,40 +1208,40 @@ function calcInput(digit, tab = null) { const currentTab = tab || getCurrentTab(); const state = getCalculatorState(currentTab); - + if (state.waitingForOperand) { state.currentValue = 0; state.waitingForOperand = false; } - + // Convert hex digit to number const digitValue = parseInt(digit, 16); if (isNaN(digitValue)) return; - + // Prevent overflow by limiting to a reasonable hex value const newValue = state.currentValue * 16 + digitValue; if (newValue <= 0xFFFFFFFFFFFFFF) { // Limit to 56 bits for safety state.currentValue = newValue; } - + updateCalculatorDisplay(currentTab); } function calcOperation(operation, tab = null) { const currentTab = tab || getCurrentTab(); const state = getCalculatorState(currentTab); - + if (operation === 'NOT') { // Unary operation - apply immediately state.currentValue = (~state.currentValue) >>> 0; // Use unsigned 32-bit updateCalculatorDisplay(currentTab); return; } - + if (state.previousValue !== 0 && !state.waitingForOperand) { calcEquals(currentTab, false); } - + state.previousValue = state.currentValue; state.operation = operation; state.waitingForOperand = true; @@ -1168,11 +1250,11 @@ function calcEquals(tab = null, updateDisplay = true) { const currentTab = tab || getCurrentTab(); const state = getCalculatorState(currentTab); - + if (state.operation && state.previousValue !== null) { const prev = state.previousValue; const curr = state.currentValue; - + try { switch (state.operation) { case '+': @@ -1214,22 +1296,22 @@ state.currentValue = (prev >> curr) >>> 0; break; } - + // Ensure positive value if (state.currentValue < 0) { state.currentValue = 0; } - + } catch (error) { alert('Calculation error: ' + error.message); state.currentValue = 0; } - + state.operation = null; state.previousValue = 0; state.waitingForOperand = true; } - + if (updateDisplay) { updateCalculatorDisplay(currentTab); } @@ -1238,19 +1320,19 @@ function calcClear(tab = null) { const currentTab = tab || getCurrentTab(); const state = getCalculatorState(currentTab); - + state.currentValue = 0; state.previousValue = 0; state.operation = null; state.waitingForOperand = false; - + updateCalculatorDisplay(currentTab); } function calcBackspace(tab = null) { const currentTab = tab || getCurrentTab(); const state = getCalculatorState(currentTab); - + if (!state.waitingForOperand) { state.currentValue = Math.floor(state.currentValue / 16); updateCalculatorDisplay(currentTab); @@ -1260,7 +1342,7 @@ function calcMemory(operation, tab = null) { const currentTab = tab || getCurrentTab(); const state = getCalculatorState(currentTab); - + switch (operation) { case 'MC': state.memory = 0; @@ -1294,13 +1376,13 @@ createTooltip(); tooltip.innerHTML = text; tooltip.style.display = 'block'; - + const rect = element.getBoundingClientRect(); const tooltipRect = tooltip.getBoundingClientRect(); - + let left = rect.left + (rect.width / 2) - (tooltipRect.width / 2); let top = rect.top - tooltipRect.height - 8; - + // Keep tooltip within viewport if (left < 10) left = 10; if (left + tooltipRect.width > window.innerWidth - 10) { @@ -1309,7 +1391,7 @@ if (top < 10) { top = rect.bottom + 8; } - + tooltip.style.left = left + 'px'; tooltip.style.top = top + 'px'; } @@ -1325,7 +1407,7 @@ const filesystems = { fat1216: { requiredFields: ['reservedSectors1216', 'numFATs1216', 'fatSizeBytes1216', 'maxRootEntries1216', 'partitionSizeInSectors1216', 'clusterSizeSectors1216'], - calculate: function() { + calculate: function () { const baseOffset = parseHex(document.getElementById('baseOffset1216').value); const sectorSize = parseHex(document.getElementById('sectorSize1216').value); const reservedSectors = parseHex(document.getElementById('reservedSectors1216').value); @@ -1339,6 +1421,7 @@ const fatStart = reservedSectors * sectorSize + baseOffset; const fatSize = numFATs * fatSizeBytes; const fatEnd = fatStart + fatSize; + const rootDirStart = fatEnd; const rootDirSize = maxRootEntries * 0x20; const dataStart = fatEnd + rootDirSize; const dataSize = partitionSizeInSectors * sectorSize - (dataStart - baseOffset); @@ -1346,11 +1429,11 @@ const numClusters = clusterSize > 0 ? Math.floor(dataSize / clusterSize) : 0; const clusterStart = dataStart + (clusterNumber - 0x2) * clusterSize; - // Store calculation formulas with actual values const calculations = { fatStart: `${reservedSectors.toString(16)} × ${sectorSize.toString(16)} + ${baseOffset.toString(16)} = ${fatStart.toString(16)}`, fatSize: `${numFATs.toString(16)} × ${fatSizeBytes.toString(16)} = ${fatSize.toString(16)}`, fatEnd: `${fatStart.toString(16)} + ${fatSize.toString(16)} = ${fatEnd.toString(16)}`, + rootDirStart: `${fatEnd.toString(16)}`, rootDirSize: `${maxRootEntries.toString(16)} × 0x20 = ${rootDirSize.toString(16)}`, dataStart: `${fatEnd.toString(16)} + ${rootDirSize.toString(16)} = ${dataStart.toString(16)}`, dataSize: `(${partitionSizeInSectors.toString(16)} × ${sectorSize.toString(16)}) - (${dataStart.toString(16)} - ${baseOffset.toString(16)}) = ${dataSize.toString(16)}`, @@ -1360,14 +1443,14 @@ }; return { - fatStart, fatSize, fatEnd, rootDirSize, dataStart, dataSize, + fatStart, fatSize, fatEnd, rootDirStart, rootDirSize, dataStart, dataSize, clusterSize, numClusters, clusterStart, calculations }; } }, fat32: { requiredFields: ['reservedSectors32', 'numFATs32', 'fatSizeBytes32', 'rootDirCluster32', 'partitionSizeInSectors32', 'clusterSizeSectors32'], - calculate: function() { + calculate: function () { const baseOffset = parseHex(document.getElementById('baseOffset32').value); const sectorSize = parseHex(document.getElementById('sectorSize32').value); const reservedSectors = parseHex(document.getElementById('reservedSectors32').value); @@ -1401,7 +1484,7 @@ }; return { - fatStart, fatSize, fatEnd, dataStart, dataSize, + fatStart, fatSize, fatEnd, dataStart, dataSize, clusterSize, numClusters, clusterStart, rootDirPos, calculations }; } @@ -1428,11 +1511,11 @@ function copyToClipboard(elementId) { const element = document.getElementById(elementId); const text = element.textContent.trim(); - + if (text === '-' || text.includes('Fehler')) { return; } - + navigator.clipboard.writeText(text).then(() => { const btn = element.parentElement.querySelector('.copy-btn'); const originalText = btn.textContent; @@ -1451,14 +1534,14 @@ document.querySelectorAll('.tab-content').forEach(content => { content.classList.remove('active'); }); - + document.querySelectorAll('.tab').forEach(tab => { tab.classList.remove('active'); }); - + document.getElementById(tabId).classList.add('active'); event.target.classList.add('active'); - + // Update calculator display when switching tabs updateCalculatorDisplay(tabId); } @@ -1472,12 +1555,13 @@ } const results = fs.calculate(); - + if (fsType === 'fat1216') { const mapping = { 'fatStart1216': ['fatStart', 'fatStart'], 'fatSize1216': ['fatSize', 'fatSize'], 'fatEnd1216': ['fatEnd', 'fatEnd'], + 'rootDirStart1216': ['rootDirStart', 'rootDirStart'], 'rootDirSize1216': ['rootDirSize', 'rootDirSize'], 'dataStart1216': ['dataStart', 'dataStart'], 'dataSize1216': ['dataSize', 'dataSize'], @@ -1485,7 +1569,6 @@ 'numClusters1216': ['numClusters', 'numClusters'], 'clusterStart1216': ['clusterStart', 'clusterStart'] }; - Object.entries(mapping).forEach(([elementId, [resultKey, calcKey]]) => { const element = document.getElementById(elementId); element.innerHTML = formatHex(results[resultKey]); @@ -1503,7 +1586,7 @@ 'clusterStart32': ['clusterStart', 'clusterStart'], 'rootDirPos32': ['rootDirPos', 'rootDirPos'] }; - + Object.entries(mapping).forEach(([elementId, [resultKey, calcKey]]) => { const element = document.getElementById(elementId); element.innerHTML = formatHex(results[resultKey]); @@ -1518,19 +1601,19 @@ } // Add event listeners - document.addEventListener('DOMContentLoaded', function() { + document.addEventListener('DOMContentLoaded', function () { // Initialize calculator displays updateCalculatorDisplay('fat1216'); updateCalculatorDisplay('fat32'); - // Real-time calculation + // Real-time calculation for required fields Object.keys(filesystems).forEach(fsType => { const fs = filesystems[fsType]; fs.requiredFields.forEach(fieldId => { const input = document.getElementById(fieldId); if (input) { - input.addEventListener('input', function() { - const allFilled = fs.requiredFields.every(id => + input.addEventListener('input', function () { + const allFilled = fs.requiredFields.every(id => document.getElementById(id).value.trim() !== '' ); if (allFilled) { @@ -1541,14 +1624,45 @@ }); }); - // Add separate listeners for cluster number fields (optional but affect results) + // Real-time calculation for constants fields + ['baseOffset1216', 'sectorSize1216'].forEach(fieldId => { + const input = document.getElementById(fieldId); + if (input) { + input.addEventListener('input', function () { + const fs = filesystems.fat1216; + const allFilled = fs.requiredFields.every(id => + document.getElementById(id).value.trim() !== '' + ); + if (allFilled) { + calculate('fat1216'); + } + }); + } + }); + + ['baseOffset32', 'sectorSize32'].forEach(fieldId => { + const input = document.getElementById(fieldId); + if (input) { + input.addEventListener('input', function () { + const fs = filesystems.fat32; + const allFilled = fs.requiredFields.every(id => + document.getElementById(id).value.trim() !== '' + ); + if (allFilled) { + calculate('fat32'); + } + }); + } + }); + + // Add separate listeners for cluster number fields ['clusterNumber1216', 'clusterNumber32'].forEach(fieldId => { const input = document.getElementById(fieldId); if (input) { - input.addEventListener('input', function() { + input.addEventListener('input', function () { const fsType = fieldId.includes('32') ? 'fat32' : 'fat1216'; const fs = filesystems[fsType]; - const allFilled = fs.requiredFields.every(id => + const allFilled = fs.requiredFields.every(id => document.getElementById(id).value.trim() !== '' ); if (allFilled) { @@ -1558,8 +1672,61 @@ } }); + // Keyboard input support for calculator + document.addEventListener('keydown', function (e) { + // Only handle keyboard input when not in an input field + if (e.target.tagName === 'INPUT') return; + + const currentTab = getCurrentTab(); + const key = e.key.toUpperCase(); + + // Handle hex digits + if (/^[0-9A-F]$/.test(key)) { + e.preventDefault(); + calcInput(key, currentTab); + } + // Handle operations + else if (key === '+') { + e.preventDefault(); + calcOperation('+', currentTab); + } + else if (key === '-') { + e.preventDefault(); + calcOperation('-', currentTab); + } + else if (key === '*') { + e.preventDefault(); + calcOperation('*', currentTab); + } + else if (key === '/') { + e.preventDefault(); + calcOperation('/', currentTab); + } + else if (key === 'ENTER' || key === '=') { + e.preventDefault(); + calcEquals(currentTab); + } + else if (key === 'ESCAPE' || key === 'C') { + e.preventDefault(); + calcClear(currentTab); + } + else if (key === 'BACKSPACE') { + e.preventDefault(); + calcBackspace(currentTab); + } + // Handle shift operations + else if (e.shiftKey && key === ',') { // < key + e.preventDefault(); + calcOperation('<<', currentTab); + } + else if (e.shiftKey && key === '.') { // > key + e.preventDefault(); + calcOperation('>>', currentTab); + } + }); + // Tooltip event listeners - document.addEventListener('mouseover', function(e) { + document.addEventListener('mouseover', function (e) { if (e.target.classList.contains('result-label')) { const formula = e.target.getAttribute('data-formula'); if (formula) { @@ -1573,7 +1740,7 @@ } }); - document.addEventListener('mouseout', function(e) { + document.addEventListener('mouseout', function (e) { if (e.target.classList.contains('result-label') || e.target.classList.contains('result-value')) { hideTooltip(); } @@ -1584,4 +1751,5 @@ }); + \ No newline at end of file