fscalc/index.html
overcuriousity d2970d42f4 calculator
2025-09-27 23:08:09 +02:00

1587 lines
71 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dateisystem-Offset-Rechner</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Consolas', 'Courier New', monospace;
background-color: #1a1a1a;
color: #e0e0e0;
line-height: 1.6;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* Header */
.header {
background-color: #2a2a2a;
border-bottom: 2px solid #3a3a3a;
padding: 15px 0;
}
.header-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
}
.logo {
font-size: 1.5em;
font-weight: bold;
color: #ffffff;
}
.nav {
display: flex;
gap: 20px;
}
.nav a {
color: #cccccc;
text-decoration: none;
transition: color 0.2s;
}
.nav a:hover {
color: #ffffff;
}
/* Main Content */
.main-content {
flex: 1;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #ffffff;
font-size: 2.2em;
font-weight: normal;
}
/* Tabs */
.tabs {
display: flex;
background-color: #2a2a2a;
border-radius: 6px 6px 0 0;
border: 1px solid #3a3a3a;
border-bottom: none;
overflow-x: auto;
}
.tab {
padding: 15px 25px;
cursor: pointer;
background-color: #2a2a2a;
border-right: 1px solid #3a3a3a;
color: #cccccc;
transition: all 0.2s;
white-space: nowrap;
min-width: 120px;
text-align: center;
}
.tab:last-child {
border-right: none;
}
.tab:hover {
background-color: #353535;
}
.tab.active {
background-color: #3a3a3a;
color: #ffffff;
border-bottom: 2px solid #666666;
}
.tab-content {
display: none;
background-color: #2a2a2a;
border: 1px solid #3a3a3a;
border-radius: 0 0 6px 6px;
padding: 20px;
}
.tab-content.active {
display: block;
}
/* Constants and Calculator Layout */
.constants-calculator-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
@media (max-width: 1024px) {
.constants-calculator-container {
grid-template-columns: 1fr;
gap: 15px;
}
}
/* Calculator Styles */
.hex-calculator {
background-color: #1a1a1a;
min-height: fit-content;
}
.calculator-container {
display: flex;
flex-direction: column;
gap: 15px;
}
.calc-display {
background-color: #111111;
border: 1px solid #404040;
border-radius: 6px;
padding: 15px;
}
.calc-input input {
width: 100%;
background-color: #2a2a2a;
border: 1px solid #555555;
border-radius: 4px;
color: #ffffff;
font-family: 'Consolas', monospace;
font-size: 18px;
font-weight: bold;
padding: 12px;
text-align: right;
margin-bottom: 12px;
}
.calc-conversions {
display: flex;
flex-direction: column;
gap: 8px;
}
.conversion-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 0;
border-bottom: 1px solid #333333;
}
.conversion-row:last-child {
border-bottom: none;
}
.conv-label {
color: #888888;
font-weight: bold;
font-size: 0.9em;
min-width: 40px;
}
.conv-value {
color: #cccccc;
font-family: 'Consolas', monospace;
font-size: 0.9em;
word-break: break-all;
text-align: right;
flex: 1;
margin-left: 10px;
}
.calc-buttons {
display: flex;
flex-direction: column;
gap: 8px;
}
.calc-row {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 6px;
}
.calc-btn {
background-color: #2a2a2a;
border: 1px solid #4a4a4a;
border-radius: 4px;
color: #ffffff;
cursor: pointer;
font-family: 'Consolas', monospace;
font-size: 0.85em;
font-weight: bold;
min-height: 40px;
padding: 8px;
text-align: center;
transition: all 0.2s;
user-select: none;
}
.calc-btn:hover {
background-color: #3a3a3a;
border-color: #666666;
}
.calc-btn:active {
background-color: #444444;
transform: translateY(1px);
}
.calc-btn.number {
background-color: #333333;
}
.calc-btn.number:hover {
background-color: #444444;
}
.calc-btn.operation {
background-color: #2a4a2a;
color: #88cc88;
}
.calc-btn.operation:hover {
background-color: #3a5a3a;
}
.calc-btn.memory {
background-color: #4a2a2a;
color: #cc8888;
font-size: 0.75em;
}
.calc-btn.memory:hover {
background-color: #5a3a3a;
}
.calc-btn.clear {
background-color: #4a2a4a;
color: #cc88cc;
}
.calc-btn.clear:hover {
background-color: #5a3a5a;
}
.calc-btn.equals {
background-color: #2a2a4a;
color: #8888cc;
}
.calc-btn.equals:hover {
background-color: #3a3a5a;
}
.calc-btn.backspace {
background-color: #4a4a2a;
color: #cccc88;
}
.calc-btn.backspace:hover {
background-color: #5a5a3a;
}
.calc-btn.wide {
grid-column: span 2;
}
@media (max-width: 768px) {
.calc-btn {
min-height: 35px;
font-size: 0.8em;
padding: 6px;
}
.calc-input input {
font-size: 16px;
padding: 10px;
}
}
/* Sections */
.section {
background-color: #252525;
border-radius: 6px;
padding: 20px;
margin-bottom: 20px;
border: 1px solid #3a3a3a;
}
.section h2 {
color: #cccccc;
margin-bottom: 15px;
border-bottom: 1px solid #3a3a3a;
padding-bottom: 8px;
font-weight: normal;
font-size: 1.3em;
}
.constants {
background-color: #202020;
}
.results {
background-color: #202020;
}
.formulas {
background-color: #1a1a1a;
}
.formula-box {
background-color: #151515;
border: 1px solid #404040;
border-radius: 4px;
padding: 15px;
margin: 10px 0;
font-family: 'Consolas', monospace;
font-size: 0.9em;
}
.formula {
margin: 8px 0;
color: #d0d0d0;
word-wrap: break-word;
}
.calculated {
color: #ffffff;
font-weight: bold;
}
.input-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 15px;
margin: 20px 0;
}
@media (max-width: 768px) {
.input-grid {
grid-template-columns: 1fr;
gap: 12px;
}
}
.input-group {
display: flex;
flex-direction: column;
}
.input-group label {
margin-bottom: 6px;
color: #cccccc;
font-weight: normal;
font-size: 0.95em;
}
.unit-indicator {
color: #88cc88;
font-weight: bold;
font-size: 0.85em;
}
.input-group input {
padding: 12px;
background-color: #333333;
border: 1px solid #4a4a4a;
border-radius: 4px;
color: #ffffff;
font-family: 'Consolas', monospace;
font-size: 14px;
transition: border-color 0.2s;
}
.input-group input:focus {
outline: none;
border-color: #666666;
background-color: #383838;
}
.result-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #3a3a3a;
position: relative;
}
.result-item:last-child {
border-bottom: none;
}
.result-label {
color: #cccccc;
font-weight: normal;
flex: 1;
cursor: help;
}
.result-value-container {
display: flex;
align-items: center;
gap: 8px;
}
.result-value {
color: #ffffff;
font-family: 'Consolas', monospace;
text-align: right;
font-weight: bold;
min-width: 120px;
cursor: help;
}
.copy-btn {
background: none;
border: none;
color: #888888;
cursor: pointer;
padding: 4px;
border-radius: 3px;
transition: all 0.2s;
font-size: 14px;
}
.copy-btn:hover {
color: #ffffff;
background-color: #404040;
}
.copy-btn:active {
color: #88cc88;
}
/* Tooltip */
.tooltip {
position: absolute;
background-color: #1a1a1a;
color: #ffffff;
padding: 8px 12px;
border-radius: 4px;
font-size: 0.85em;
border: 1px solid #555555;
z-index: 1000;
max-width: 400px;
word-wrap: break-word;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
font-family: 'Consolas', monospace;
line-height: 1.4;
}
@media (max-width: 600px) {
.result-item {
flex-direction: column;
align-items: flex-start;
gap: 5px;
}
.result-value {
text-align: left;
min-width: auto;
}
}
@media (max-width: 600px) {
.header-content {
flex-direction: column;
gap: 10px;
}
.nav {
justify-content: center;
}
}
.error {
color: #ff8888;
font-style: italic;
}
/* Footer */
.footer {
background-color: #2a2a2a;
border-top: 1px solid #3a3a3a;
padding: 20px 0;
margin-top: 40px;
}
.footer-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 20px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
}
.footer-section h3 {
color: #ffffff;
margin-bottom: 10px;
font-size: 1.1em;
}
.footer-section p,
.footer-section a {
color: #cccccc;
font-size: 0.9em;
text-decoration: none;
margin-bottom: 5px;
display: block;
}
.footer-section a:hover {
color: #ffffff;
}
.footer-bottom {
text-align: center;
padding-top: 20px;
margin-top: 20px;
border-top: 1px solid #3a3a3a;
color: #888888;
font-size: 0.85em;
}
@media (max-width: 768px) {
.main-content {
padding: 15px;
}
h1 {
font-size: 1.8em;
margin-bottom: 20px;
}
.section {
padding: 15px;
}
.formula-box {
padding: 12px;
font-size: 0.85em;
}
.tab {
padding: 12px 15px;
min-width: 100px;
}
}
@media (min-width: 1200px) {
.input-grid {
grid-template-columns: repeat(3, 1fr);
}
}
</style>
</head>
<body>
<header class="header">
<div class="header-content">
<div class="logo">Dateisystem-Offset-Rechner</div>
<nav class="nav">
<a href="#home">Home</a>
<a href="mailto:mstoeck3@hs-mittweida.de">Contact</a>
</nav>
</div>
</header>
<main class="main-content">
<div class="container">
<h1>Dateisystem-Offset-Rechner</h1>
<div class="tabs">
<div class="tab active" onclick="switchTab('fat1216')">FAT12/16</div>
<div class="tab" onclick="switchTab('fat32')">FAT32</div>
</div>
<!-- FAT12/16 Tab -->
<div class="tab-content active" id="fat1216">
<div class="constants-calculator-container">
<div class="section constants">
<h2>Konstanten</h2>
<div class="input-grid">
<div class="input-group">
<label for="baseOffset1216">Base Offset <span class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="baseOffset1216" value="0x0" placeholder="0x0">
</div>
<div class="input-group">
<label for="sectorSize1216">Größe eines Sektors <span class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="sectorSize1216" value="0x200" placeholder="0x200">
</div>
</div>
</div>
<div class="section hex-calculator">
<h2>Hex Calculator</h2>
<div class="calculator-container">
<div class="calc-display">
<div class="calc-input">
<input type="text" id="calcInput" placeholder="0x0" readonly>
</div>
<div class="calc-conversions">
<div class="conversion-row">
<span class="conv-label">HEX:</span>
<span class="conv-value" id="hexValue">0x0</span>
</div>
<div class="conversion-row">
<span class="conv-label">DEC:</span>
<span class="conv-value" id="decValue">0</span>
</div>
<div class="conversion-row">
<span class="conv-label">BIN:</span>
<span class="conv-value" id="binValue">0b0</span>
</div>
</div>
</div>
<div class="calc-buttons">
<div class="calc-row">
<button class="calc-btn memory" onclick="calcMemory('MC')">MC</button>
<button class="calc-btn memory" onclick="calcMemory('MR')">MR</button>
<button class="calc-btn memory" onclick="calcMemory('M+')">M+</button>
<button class="calc-btn memory" onclick="calcMemory('M-')">M-</button>
<button class="calc-btn clear" onclick="calcClear()">C</button>
</div>
<div class="calc-row">
<button class="calc-btn number" onclick="calcInput('A')">A</button>
<button class="calc-btn number" onclick="calcInput('B')">B</button>
<button class="calc-btn number" onclick="calcInput('C')">C</button>
<button class="calc-btn number" onclick="calcInput('D')">D</button>
<button class="calc-btn operation" onclick="calcOperation('<<')">&lt;&lt;</button>
</div>
<div class="calc-row">
<button class="calc-btn number" onclick="calcInput('E')">E</button>
<button class="calc-btn number" onclick="calcInput('F')">F</button>
<button class="calc-btn number" onclick="calcInput('7')">7</button>
<button class="calc-btn number" onclick="calcInput('8')">8</button>
<button class="calc-btn operation" onclick="calcOperation('>>')">&gt;&gt;</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('AND')">AND</button>
<button class="calc-btn operation" onclick="calcOperation('OR')">OR</button>
<button class="calc-btn number" onclick="calcInput('9')">9</button>
<button class="calc-btn operation" onclick="calcOperation('/')">/</button>
<button class="calc-btn operation" onclick="calcOperation('MOD')">MOD</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('XOR')">XOR</button>
<button class="calc-btn operation" onclick="calcOperation('NOT')">NOT</button>
<button class="calc-btn number" onclick="calcInput('4')">4</button>
<button class="calc-btn number" onclick="calcInput('5')">5</button>
<button class="calc-btn number" onclick="calcInput('6')">6</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('*')">*</button>
<button class="calc-btn number" onclick="calcInput('1')">1</button>
<button class="calc-btn number" onclick="calcInput('2')">2</button>
<button class="calc-btn number" onclick="calcInput('3')">3</button>
<button class="calc-btn operation" onclick="calcOperation('-')">-</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('+')">+</button>
<button class="calc-btn number wide" onclick="calcInput('0')">0</button>
<button class="calc-btn backspace" onclick="calcBackspace()"></button>
<button class="calc-btn equals" onclick="calcEquals()">=</button>
</div>
</div>
</div>
</div>
</div>
<div class="section">
<h2>Eingabeparameter</h2>
<div class="input-grid">
<div class="input-group">
<label for="reservedSectors1216">Anzahl reservierter Sektoren <span class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="reservedSectors1216" placeholder="0x1">
</div>
<div class="input-group">
<label for="numFATs1216">Anzahl FATs <span class="unit-indicator">(Anzahl)</span>:</label>
<input type="text" id="numFATs1216" placeholder="0x2">
</div>
<div class="input-group">
<label for="fatSizeBytes1216">Größe einer FAT <span class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="fatSizeBytes1216" placeholder="0x1000">
</div>
<div class="input-group">
<label for="maxRootEntries1216">Max. Wurzelverzeichnis-Einträge <span class="unit-indicator">(Anzahl)</span>:</label>
<input type="text" id="maxRootEntries1216" placeholder="0x200">
</div>
<div class="input-group">
<label for="partitionSizeInSectors1216">Größe Partition <span class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="partitionSizeInSectors1216" placeholder="0x4015">
</div>
<div class="input-group">
<label for="clusterSizeSectors1216">Größe eines Clusters <span class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="clusterSizeSectors1216" placeholder="0x1">
</div>
<div class="input-group">
<label for="clusterNumber1216">Cluster Nummer für Position <span class="unit-indicator">(Nummer)</span>:</label>
<input type="text" id="clusterNumber1216" placeholder="0x2">
</div>
</div>
</div>
<div class="section results">
<h2>Berechnete Werte</h2>
<div id="results1216">
<div class="result-item">
<span class="result-label" data-formula="reservedSectors × sectorSize + baseOffset">Beginn FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatStart1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatStart1216')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="numFATs × fatSizeBytes">Größe FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatSize1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatSize1216')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatStart + fatSize">Ende FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatEnd1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatEnd1216')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="maxRootEntries × 0x20">Größe Wurzelverzeichnis:</span>
<div class="result-value-container">
<span class="result-value" id="rootDirSize1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('rootDirSize1216')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatEnd + rootDirSize">Beginn Daten-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="dataStart1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('dataStart1216')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="(partitionSizeInSectors × sectorSize) - (dataStart - baseOffset)">Größe Daten-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="dataSize1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('dataSize1216')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="sectorSize × clusterSizeSectors">Größe eines Clusters:</span>
<div class="result-value-container">
<span class="result-value" id="clusterSize1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('clusterSize1216')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="dataSize ÷ clusterSize">Anzahl Cluster:</span>
<div class="result-value-container">
<span class="result-value" id="numClusters1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('numClusters1216')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="dataStart + (clusterNumber - 0x2) × clusterSize">Beginn Cluster:</span>
<div class="result-value-container">
<span class="result-value" id="clusterStart1216" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('clusterStart1216')" title="Copy to clipboard">📋</button>
</div>
</div>
</div>
</div>
<div class="section formulas">
<h2>Berechnungsformeln FAT12/16</h2>
<div class="formula-box">
<div class="formula"><span class="calculated">Beginn FAT-Bereich</span> = Anzahl reservierter Sektoren × Größe eines Sektors + Base Offset</div>
<div class="formula"><span class="calculated">Größe FAT-Bereich</span> = Anzahl FATs × Größe einer FAT</div>
<div class="formula"><span class="calculated">Ende FAT-Bereich</span> = Beginn FAT-Bereich + Größe FAT-Bereich</div>
<div class="formula"><span class="calculated">Größe Wurzelverzeichnis</span> = Anzahl max. Wurzelverzeichnis-Einträge × 0x20</div>
<div class="formula"><span class="calculated">Beginn Daten-Bereich</span> = Ende FAT-Bereich + Größe Wurzelverzeichnis</div>
<div class="formula"><span class="calculated">Größe Daten-Bereich</span> = (Größe Partition in Sektoren × Größe eines Sektors) - (Beginn Daten-Bereich - Base Offset)</div>
<div class="formula"><span class="calculated">Größe eines Clusters</span> = Größe eines Sektors × Größe eines Clusters in Sektoren</div>
<div class="formula"><span class="calculated">Anzahl Cluster</span> = Größe Daten-Bereich ÷ Größe eines Clusters</div>
<div class="formula"><span class="calculated">Beginn Cluster</span> = Beginn Daten-Bereich + (Cluster - 0x2) × Größe eines Clusters</div>
</div>
</div>
</div>
<!-- FAT32 Tab -->
<div class="tab-content" id="fat32">
<div class="constants-calculator-container">
<div class="section constants">
<h2>Konstanten</h2>
<div class="input-grid">
<div class="input-group">
<label for="baseOffset32">Base Offset <span class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="baseOffset32" value="0x0" placeholder="0x0">
</div>
<div class="input-group">
<label for="sectorSize32">Größe eines Sektors <span class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="sectorSize32" value="0x200" placeholder="0x200">
</div>
</div>
</div>
<div class="section hex-calculator">
<h2>Hex Calculator</h2>
<div class="calculator-container">
<div class="calc-display">
<div class="calc-input">
<input type="text" id="calcInput32" placeholder="0x0" readonly>
</div>
<div class="calc-conversions">
<div class="conversion-row">
<span class="conv-label">HEX:</span>
<span class="conv-value" id="hexValue32">0x0</span>
</div>
<div class="conversion-row">
<span class="conv-label">DEC:</span>
<span class="conv-value" id="decValue32">0</span>
</div>
<div class="conversion-row">
<span class="conv-label">BIN:</span>
<span class="conv-value" id="binValue32">0b0</span>
</div>
</div>
</div>
<div class="calc-buttons">
<div class="calc-row">
<button class="calc-btn memory" onclick="calcMemory('MC', 'fat32')">MC</button>
<button class="calc-btn memory" onclick="calcMemory('MR', 'fat32')">MR</button>
<button class="calc-btn memory" onclick="calcMemory('M+', 'fat32')">M+</button>
<button class="calc-btn memory" onclick="calcMemory('M-', 'fat32')">M-</button>
<button class="calc-btn clear" onclick="calcClear('fat32')">C</button>
</div>
<div class="calc-row">
<button class="calc-btn number" onclick="calcInput('A', 'fat32')">A</button>
<button class="calc-btn number" onclick="calcInput('B', 'fat32')">B</button>
<button class="calc-btn number" onclick="calcInput('C', 'fat32')">C</button>
<button class="calc-btn number" onclick="calcInput('D', 'fat32')">D</button>
<button class="calc-btn operation" onclick="calcOperation('<<', 'fat32')">&lt;&lt;</button>
</div>
<div class="calc-row">
<button class="calc-btn number" onclick="calcInput('E', 'fat32')">E</button>
<button class="calc-btn number" onclick="calcInput('F', 'fat32')">F</button>
<button class="calc-btn number" onclick="calcInput('7', 'fat32')">7</button>
<button class="calc-btn number" onclick="calcInput('8', 'fat32')">8</button>
<button class="calc-btn operation" onclick="calcOperation('>>', 'fat32')">&gt;&gt;</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('AND', 'fat32')">AND</button>
<button class="calc-btn operation" onclick="calcOperation('OR', 'fat32')">OR</button>
<button class="calc-btn number" onclick="calcInput('9', 'fat32')">9</button>
<button class="calc-btn operation" onclick="calcOperation('/', 'fat32')">/</button>
<button class="calc-btn operation" onclick="calcOperation('MOD', 'fat32')">MOD</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('XOR', 'fat32')">XOR</button>
<button class="calc-btn operation" onclick="calcOperation('NOT', 'fat32')">NOT</button>
<button class="calc-btn number" onclick="calcInput('4', 'fat32')">4</button>
<button class="calc-btn number" onclick="calcInput('5', 'fat32')">5</button>
<button class="calc-btn number" onclick="calcInput('6', 'fat32')">6</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('*', 'fat32')">*</button>
<button class="calc-btn number" onclick="calcInput('1', 'fat32')">1</button>
<button class="calc-btn number" onclick="calcInput('2', 'fat32')">2</button>
<button class="calc-btn number" onclick="calcInput('3', 'fat32')">3</button>
<button class="calc-btn operation" onclick="calcOperation('-', 'fat32')">-</button>
</div>
<div class="calc-row">
<button class="calc-btn operation" onclick="calcOperation('+', 'fat32')">+</button>
<button class="calc-btn number wide" onclick="calcInput('0', 'fat32')">0</button>
<button class="calc-btn backspace" onclick="calcBackspace('fat32')"></button>
<button class="calc-btn equals" onclick="calcEquals('fat32')">=</button>
</div>
</div>
</div>
</div>
</div>
<div class="section">
<h2>Eingabeparameter</h2>
<div class="input-grid">
<div class="input-group">
<label for="reservedSectors32">Anzahl reservierter Sektoren <span class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="reservedSectors32" placeholder="0x20">
</div>
<div class="input-group">
<label for="numFATs32">Anzahl FATs <span class="unit-indicator">(Anzahl)</span>:</label>
<input type="text" id="numFATs32" placeholder="0x2">
</div>
<div class="input-group">
<label for="fatSizeBytes32">Größe einer FAT <span class="unit-indicator">(Bytes)</span>:</label>
<input type="text" id="fatSizeBytes32" placeholder="0x10000">
</div>
<div class="input-group">
<label for="rootDirCluster32">Root Directory Cluster <span class="unit-indicator">(Nummer)</span>:</label>
<input type="text" id="rootDirCluster32" placeholder="0x2">
</div>
<div class="input-group">
<label for="partitionSizeInSectors32">Größe Partition <span class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="partitionSizeInSectors32" placeholder="0x20000">
</div>
<div class="input-group">
<label for="clusterSizeSectors32">Größe eines Clusters <span class="unit-indicator">(Sektoren)</span>:</label>
<input type="text" id="clusterSizeSectors32" placeholder="0x8">
</div>
<div class="input-group">
<label for="clusterNumber32">Cluster Nummer für Position <span class="unit-indicator">(Nummer)</span>:</label>
<input type="text" id="clusterNumber32" placeholder="0x2">
</div>
</div>
</div>
<div class="section results">
<h2>Berechnete Werte</h2>
<div id="results32">
<div class="result-item">
<span class="result-label" data-formula="reservedSectors × sectorSize + baseOffset">Beginn FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatStart32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatStart32')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="numFATs × fatSizeBytes">Größe FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatSize32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatSize32')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatStart + fatSize">Ende FAT-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="fatEnd32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('fatEnd32')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="fatEnd">Beginn Daten-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="dataStart32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('dataStart32')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="(partitionSizeInSectors × sectorSize) - (dataStart - baseOffset)">Größe Daten-Bereich:</span>
<div class="result-value-container">
<span class="result-value" id="dataSize32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('dataSize32')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="sectorSize × clusterSizeSectors">Größe eines Clusters:</span>
<div class="result-value-container">
<span class="result-value" id="clusterSize32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('clusterSize32')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="dataSize ÷ clusterSize">Anzahl Cluster:</span>
<div class="result-value-container">
<span class="result-value" id="numClusters32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('numClusters32')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="dataStart + (clusterNumber - 0x2) × clusterSize">Beginn Cluster:</span>
<div class="result-value-container">
<span class="result-value" id="clusterStart32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('clusterStart32')" title="Copy to clipboard">📋</button>
</div>
</div>
<div class="result-item">
<span class="result-label" data-formula="dataStart + (rootDirCluster - 0x2) × clusterSize">Root Directory Position:</span>
<div class="result-value-container">
<span class="result-value" id="rootDirPos32" data-result-formula="">-</span>
<button class="copy-btn" onclick="copyToClipboard('rootDirPos32')" title="Copy to clipboard">📋</button>
</div>
</div>
</div>
</div>
<div class="section formulas">
<h2>Berechnungsformeln FAT32</h2>
<div class="formula-box">
<div class="formula"><span class="calculated">Beginn FAT-Bereich</span> = Anzahl reservierter Sektoren × Größe eines Sektors + Base Offset</div>
<div class="formula"><span class="calculated">Größe FAT-Bereich</span> = Anzahl FATs × Größe einer FAT</div>
<div class="formula"><span class="calculated">Ende FAT-Bereich</span> = Beginn FAT-Bereich + Größe FAT-Bereich</div>
<div class="formula"><span class="calculated">Beginn Daten-Bereich</span> = Ende FAT-Bereich (kein festes Root Directory)</div>
<div class="formula"><span class="calculated">Größe Daten-Bereich</span> = (Größe Partition in Sektoren × Größe eines Sektors) - (Beginn Daten-Bereich - Base Offset)</div>
<div class="formula"><span class="calculated">Größe eines Clusters</span> = Größe eines Sektors × Größe eines Clusters in Sektoren</div>
<div class="formula"><span class="calculated">Anzahl Cluster</span> = Größe Daten-Bereich ÷ Größe eines Clusters</div>
<div class="formula"><span class="calculated">Beginn Cluster</span> = Beginn Daten-Bereich + (Cluster - 0x2) × Größe eines Clusters</div>
<div class="formula"><span class="calculated">Root Directory Position</span> = Beginn Daten-Bereich + (Root Directory Cluster - 0x2) × Größe eines Clusters</div>
</div>
</div>
</div>
</div>
</main>
<footer class="footer">
<div class="footer-content">
<div class="footer-section">
<h3>About</h3>
<p>Offset calculator for educational and forensic purposes.</p>
<p>Version 0.2.0</p>
</div>
<div class="footer-section">
<h3>Support</h3>
<a href="mailto:mstoeck3@hs-mittweida.de">Contact Support</a>
<a href="https://git.cc24.dev/mstoeck3/fscalc/issues/new">Report Bug</a>
</div>
<div class="footer-section">
<h3>Legal</h3>
<a href="https://git.cc24.dev/mstoeck3/fscalc/src/branch/main/LICENSE">License</a>
</div>
<div class="footer-section">
<h3>Connect</h3>
<a href="https://git.cc24.dev/mstoeck3/fscalc">Gitea Repository</a>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2025 Offset Calculator. All rights reserved. | Built with ❤️ for computer science education.</p>
</div>
</footer>
<script>
// Global tooltip element
let tooltip = null;
// Calculator state
const calculatorState = {
fat1216: {
currentValue: 0,
previousValue: 0,
operation: null,
waitingForOperand: false,
memory: 0
},
fat32: {
currentValue: 0,
previousValue: 0,
operation: null,
waitingForOperand: false,
memory: 0
}
};
function getCurrentTab() {
const activeTab = document.querySelector('.tab-content.active');
return activeTab.id === 'fat32' ? 'fat32' : 'fat1216';
}
function getCalculatorState(tab = null) {
const currentTab = tab || getCurrentTab();
return currentTab === 'fat32' ? calculatorState.fat32 : calculatorState.fat1216;
}
function updateCalculatorDisplay(tab = null) {
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;
binElement.textContent = binStr;
}
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;
}
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 '+':
state.currentValue = prev + curr;
break;
case '-':
state.currentValue = prev - curr;
break;
case '*':
state.currentValue = prev * curr;
break;
case '/':
if (curr === 0) {
alert('Division by zero!');
return;
}
state.currentValue = Math.floor(prev / curr);
break;
case 'MOD':
if (curr === 0) {
alert('Modulo by zero!');
return;
}
state.currentValue = prev % curr;
break;
case 'AND':
state.currentValue = (prev & curr) >>> 0;
break;
case 'OR':
state.currentValue = (prev | curr) >>> 0;
break;
case 'XOR':
state.currentValue = (prev ^ curr) >>> 0;
break;
case '<<':
state.currentValue = (prev << curr) >>> 0;
break;
case '>>':
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);
}
}
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);
}
}
function calcMemory(operation, tab = null) {
const currentTab = tab || getCurrentTab();
const state = getCalculatorState(currentTab);
switch (operation) {
case 'MC':
state.memory = 0;
break;
case 'MR':
state.currentValue = state.memory;
state.waitingForOperand = false;
updateCalculatorDisplay(currentTab);
break;
case 'M+':
state.memory += state.currentValue;
break;
case 'M-':
state.memory -= state.currentValue;
break;
}
}
// Create tooltip element
function createTooltip() {
if (!tooltip) {
tooltip = document.createElement('div');
tooltip.className = 'tooltip';
tooltip.style.display = 'none';
document.body.appendChild(tooltip);
}
}
// Show tooltip
function showTooltip(element, text) {
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) {
left = window.innerWidth - tooltipRect.width - 10;
}
if (top < 10) {
top = rect.bottom + 8;
}
tooltip.style.left = left + 'px';
tooltip.style.top = top + 'px';
}
// Hide tooltip
function hideTooltip() {
if (tooltip) {
tooltip.style.display = 'none';
}
}
// Filesystem calculation implementations
const filesystems = {
fat1216: {
requiredFields: ['reservedSectors1216', 'numFATs1216', 'fatSizeBytes1216', 'maxRootEntries1216', 'partitionSizeInSectors1216', 'clusterSizeSectors1216'],
calculate: function() {
const baseOffset = parseHex(document.getElementById('baseOffset1216').value);
const sectorSize = parseHex(document.getElementById('sectorSize1216').value);
const reservedSectors = parseHex(document.getElementById('reservedSectors1216').value);
const numFATs = parseHex(document.getElementById('numFATs1216').value);
const fatSizeBytes = parseHex(document.getElementById('fatSizeBytes1216').value);
const maxRootEntries = parseHex(document.getElementById('maxRootEntries1216').value);
const partitionSizeInSectors = parseHex(document.getElementById('partitionSizeInSectors1216').value);
const clusterSizeSectors = parseHex(document.getElementById('clusterSizeSectors1216').value);
const clusterNumber = parseHex(document.getElementById('clusterNumber1216').value);
const fatStart = reservedSectors * sectorSize + baseOffset;
const fatSize = numFATs * fatSizeBytes;
const fatEnd = fatStart + fatSize;
const rootDirSize = maxRootEntries * 0x20;
const dataStart = fatEnd + rootDirSize;
const dataSize = partitionSizeInSectors * sectorSize - (dataStart - baseOffset);
const clusterSize = sectorSize * clusterSizeSectors;
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)}`,
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)}`,
clusterSize: `${sectorSize.toString(16)} × ${clusterSizeSectors.toString(16)} = ${clusterSize.toString(16)}`,
numClusters: `${dataSize.toString(16)} ÷ ${clusterSize.toString(16)} = ${numClusters.toString(16)}`,
clusterStart: `${dataStart.toString(16)} + (${clusterNumber.toString(16)} - 0x2) × ${clusterSize.toString(16)} = ${clusterStart.toString(16)}`
};
return {
fatStart, fatSize, fatEnd, rootDirSize, dataStart, dataSize,
clusterSize, numClusters, clusterStart, calculations
};
}
},
fat32: {
requiredFields: ['reservedSectors32', 'numFATs32', 'fatSizeBytes32', 'rootDirCluster32', 'partitionSizeInSectors32', 'clusterSizeSectors32'],
calculate: function() {
const baseOffset = parseHex(document.getElementById('baseOffset32').value);
const sectorSize = parseHex(document.getElementById('sectorSize32').value);
const reservedSectors = parseHex(document.getElementById('reservedSectors32').value);
const numFATs = parseHex(document.getElementById('numFATs32').value);
const fatSizeBytes = parseHex(document.getElementById('fatSizeBytes32').value);
const rootDirCluster = parseHex(document.getElementById('rootDirCluster32').value);
const partitionSizeInSectors = parseHex(document.getElementById('partitionSizeInSectors32').value);
const clusterSizeSectors = parseHex(document.getElementById('clusterSizeSectors32').value);
const clusterNumber = parseHex(document.getElementById('clusterNumber32').value);
const fatStart = reservedSectors * sectorSize + baseOffset;
const fatSize = numFATs * fatSizeBytes;
const fatEnd = fatStart + fatSize;
const dataStart = fatEnd;
const dataSize = partitionSizeInSectors * sectorSize - (dataStart - baseOffset);
const clusterSize = sectorSize * clusterSizeSectors;
const numClusters = clusterSize > 0 ? Math.floor(dataSize / clusterSize) : 0;
const clusterStart = dataStart + (clusterNumber - 0x2) * clusterSize;
const rootDirPos = dataStart + (rootDirCluster - 0x2) * clusterSize;
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)}`,
dataStart: `${fatEnd.toString(16)}`,
dataSize: `(${partitionSizeInSectors.toString(16)} × ${sectorSize.toString(16)}) - (${dataStart.toString(16)} - ${baseOffset.toString(16)}) = ${dataSize.toString(16)}`,
clusterSize: `${sectorSize.toString(16)} × ${clusterSizeSectors.toString(16)} = ${clusterSize.toString(16)}`,
numClusters: `${dataSize.toString(16)} ÷ ${clusterSize.toString(16)} = ${numClusters.toString(16)}`,
clusterStart: `${dataStart.toString(16)} + (${clusterNumber.toString(16)} - 0x2) × ${clusterSize.toString(16)} = ${clusterStart.toString(16)}`,
rootDirPos: `${dataStart.toString(16)} + (${rootDirCluster.toString(16)} - 0x2) × ${clusterSize.toString(16)} = ${rootDirPos.toString(16)}`
};
return {
fatStart, fatSize, fatEnd, dataStart, dataSize,
clusterSize, numClusters, clusterStart, rootDirPos, calculations
};
}
}
};
function parseHex(value) {
if (!value) return 0;
let cleanValue = value.toString().trim();
if (cleanValue.startsWith('0x') || cleanValue.startsWith('0X')) {
cleanValue = cleanValue.substring(2);
}
const parsed = parseInt(cleanValue, 16);
return isNaN(parsed) ? 0 : parsed;
}
function formatHex(value) {
if (isNaN(value) || value < 0) {
return '<span class="error">Fehler</span>';
}
return '0x' + value.toString(16).toUpperCase();
}
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;
btn.textContent = '✓';
btn.style.color = '#88cc88';
setTimeout(() => {
btn.textContent = originalText;
btn.style.color = '';
}, 1000);
}).catch(err => {
console.error('Failed to copy to clipboard:', err);
});
}
function switchTab(tabId) {
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);
}
function calculate(fsType) {
try {
const fs = filesystems[fsType];
if (!fs) {
alert('Unknown filesystem type: ' + fsType);
return;
}
const results = fs.calculate();
if (fsType === 'fat1216') {
const mapping = {
'fatStart1216': ['fatStart', 'fatStart'],
'fatSize1216': ['fatSize', 'fatSize'],
'fatEnd1216': ['fatEnd', 'fatEnd'],
'rootDirSize1216': ['rootDirSize', 'rootDirSize'],
'dataStart1216': ['dataStart', 'dataStart'],
'dataSize1216': ['dataSize', 'dataSize'],
'clusterSize1216': ['clusterSize', 'clusterSize'],
'numClusters1216': ['numClusters', 'numClusters'],
'clusterStart1216': ['clusterStart', 'clusterStart']
};
Object.entries(mapping).forEach(([elementId, [resultKey, calcKey]]) => {
const element = document.getElementById(elementId);
element.innerHTML = formatHex(results[resultKey]);
element.setAttribute('data-result-formula', results.calculations[calcKey]);
});
} else if (fsType === 'fat32') {
const mapping = {
'fatStart32': ['fatStart', 'fatStart'],
'fatSize32': ['fatSize', 'fatSize'],
'fatEnd32': ['fatEnd', 'fatEnd'],
'dataStart32': ['dataStart', 'dataStart'],
'dataSize32': ['dataSize', 'dataSize'],
'clusterSize32': ['clusterSize', 'clusterSize'],
'numClusters32': ['numClusters', 'numClusters'],
'clusterStart32': ['clusterStart', 'clusterStart'],
'rootDirPos32': ['rootDirPos', 'rootDirPos']
};
Object.entries(mapping).forEach(([elementId, [resultKey, calcKey]]) => {
const element = document.getElementById(elementId);
element.innerHTML = formatHex(results[resultKey]);
element.setAttribute('data-result-formula', results.calculations[calcKey]);
});
}
} catch (error) {
alert('Fehler bei der Berechnung: ' + error.message);
console.error('Calculation error:', error);
}
}
// Add event listeners
document.addEventListener('DOMContentLoaded', function() {
// Initialize calculator displays
updateCalculatorDisplay('fat1216');
updateCalculatorDisplay('fat32');
// Real-time calculation
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 =>
document.getElementById(id).value.trim() !== ''
);
if (allFilled) {
calculate(fsType);
}
});
}
});
});
// Add separate listeners for cluster number fields (optional but affect results)
['clusterNumber1216', 'clusterNumber32'].forEach(fieldId => {
const input = document.getElementById(fieldId);
if (input) {
input.addEventListener('input', function() {
const fsType = fieldId.includes('32') ? 'fat32' : 'fat1216';
const fs = filesystems[fsType];
const allFilled = fs.requiredFields.every(id =>
document.getElementById(id).value.trim() !== ''
);
if (allFilled) {
calculate(fsType);
}
});
}
});
// Tooltip event listeners
document.addEventListener('mouseover', function(e) {
if (e.target.classList.contains('result-label')) {
const formula = e.target.getAttribute('data-formula');
if (formula) {
showTooltip(e.target, `Formula: ${formula}`);
}
} else if (e.target.classList.contains('result-value')) {
const formula = e.target.getAttribute('data-result-formula');
if (formula && formula !== '') {
showTooltip(e.target, `Calculation: ${formula}`);
}
}
});
document.addEventListener('mouseout', function(e) {
if (e.target.classList.contains('result-label') || e.target.classList.contains('result-value')) {
hideTooltip();
}
});
// Hide tooltip when scrolling
document.addEventListener('scroll', hideTooltip);
});
</script>
</body>
</html>