Fix max capacity check

This commit is contained in:
Alexander Wainwright
2025-12-18 20:39:35 +10:00
parent 875e29841f
commit 9d20b58547

View File

@@ -1,4 +1,13 @@
document.addEventListener('DOMContentLoaded', () => {
// --- 0. CONSTANTS ---
// Limits based on Version 40 (Byte Mode)
const MAX_CAPACITY = {
'L': 2950,
'M': 2328,
'Q': 1660,
'H': 1270
};
// --- 1. DOM REFERENCES ---
const qrContainer = document.getElementById('qr-container');
const downloadBtn = document.getElementById('btn-download');
@@ -101,20 +110,18 @@ document.addEventListener('DOMContentLoaded', () => {
const blob = new Blob([textData]);
const bytes = blob.size;
// Limits based on Version 40 (Byte Mode)
const maxCapacityMap = { 'L': 2950, 'M': 2328, 'Q': 1660, 'H': 1270 };
const maxBytes = maxCapacityMap[optEcc.value] || 1270;
const maxBytes = MAX_CAPACITY[optEcc.value] || 1270;
const raw_usage = Math.round((bytes / maxBytes) * 100);
const usage = Math.min(100, raw_usage);
const rawUsage = Math.round((bytes / maxBytes) * 100);
const usage = Math.min(100, rawUsage);
if (usage > 50) {
capMeter.style.display = 'block';
capBar.style.width = `${usage}%`;
capText.textContent = `${usage}% (${bytes} / ${maxBytes} B)`;
// Update Text Labels
if (raw_usage <= 100) {
if (bytes <= maxBytes) {
capLabel.textContent = 'CAPACITY';
} else {
capLabel.textContent = 'OVER CAPACITY';
@@ -126,8 +133,7 @@ document.addEventListener('DOMContentLoaded', () => {
capText.style.color = 'red';
capLabel.style.color = 'red';
} else {
// Normal Level: Remove inline styles.
// This lets CSS var(--text-color) take over (Black in Light, White in Dark)
// Normal Level: Let CSS variables handle it (Black/White)
capBar.style.backgroundColor = '';
capText.style.color = '';
capLabel.style.color = '';
@@ -165,7 +171,6 @@ document.addEventListener('DOMContentLoaded', () => {
// 4. Handle Empty State
if (!textData || textData.trim() === '') {
// Only clear if we are the latest render
if (mySeq === renderSeq) {
qrContainer.innerHTML = '';
downloadBtn.disabled = true;
@@ -193,14 +198,13 @@ document.addEventListener('DOMContentLoaded', () => {
const modules = instance._oQRCode.modules;
const svgString = generateSVGString(modules, size, colorDark, colorLight);
// SVG is instant, but check sequence just in case
if (mySeq === renderSeq) {
qrContainer.innerHTML = svgString;
downloadBtn.disabled = false;
}
}
else {
// PNG Mode (Async with Race Condition Protection)
// PNG Mode
const canvas = tempContainer.querySelector('canvas');
if (canvas) {
const dataUrl = canvas.toDataURL("image/png");
@@ -212,7 +216,6 @@ document.addEventListener('DOMContentLoaded', () => {
newImg.style.imageRendering = 'pixelated';
newImg.src = dataUrl;
// Use decode() if available for seamless paint
const ready = newImg.decode
? newImg.decode()
: new Promise((resolve, reject) => {
@@ -221,15 +224,11 @@ document.addEventListener('DOMContentLoaded', () => {
});
ready.then(() => {
// [CHECK] If a newer render started while we were decoding, ABORT.
if (mySeq !== renderSeq) return;
qrContainer.replaceChildren(newImg);
downloadBtn.disabled = false;
}).catch(() => {
// Even on error, respect the sequence
if (mySeq !== renderSeq) return;
// Fallback: Just shove it in
qrContainer.replaceChildren(newImg);
downloadBtn.disabled = false;
});
@@ -237,13 +236,12 @@ document.addEventListener('DOMContentLoaded', () => {
}
} catch (e) {
// Error Handling (Sequence Check Not Strictly Needed here but good practice)
if (mySeq !== renderSeq) return;
const blob = new Blob([textData]);
const bytes = blob.size;
const maxCapacityMap = { 'L': 2953, 'M': 2331, 'Q': 1663, 'H': 1273 };
const maxBytes = maxCapacityMap[optEcc.value] || 1273;
const maxBytes = MAX_CAPACITY[optEcc.value] || 1270;
if (bytes >= maxBytes) {
renderError("CAPACITY EXCEEDED", "REDUCE TEXT OR LOWER ECC LEVEL");
@@ -265,16 +263,13 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
// --- 5. RESET LOGIC (Button Only) ---
// --- 5. RESET LOGIC ---
function resetApp() {
// 1. Clear Content Inputs
const inputs = document.querySelectorAll('.input-form input, .input-form textarea');
inputs.forEach(el => el.value = '');
// 2. Reset Mode to Text
modeSelector.value = 'text';
// 3. Reset Advanced Configuration to Defaults
optEcc.value = 'H';
optSize.value = '256';
@@ -284,25 +279,21 @@ document.addEventListener('DOMContentLoaded', () => {
optBg.value = '#ffffff';
hexBg.textContent = '#FFFFFF';
// Reset Format Radio to PNG
for (const r of fmtRadios) {
if (r.value === 'png') r.checked = true;
}
// 4. Update UI Classes (Show Text Form)
document.querySelectorAll('.input-form').forEach(f => f.classList.remove('active'));
document.getElementById('form-text').classList.add('active');
// 5. Update Output
handleUpdate(true);
// 6. Focus the first box
const firstField = document.querySelector('#form-text textarea');
if (firstField) firstField.focus();
}
// --- 6. LISTENERS ---
// (Listeners remain the same)
[optEcc, optSize, optFg, optBg].forEach(el => {
el.addEventListener('input', () => handleUpdate(false));
});
@@ -325,7 +316,6 @@ document.addEventListener('DOMContentLoaded', () => {
form.addEventListener('input', () => handleUpdate(false));
});
// Clear Button
if (clearBtn) {
clearBtn.addEventListener('click', resetApp);
}
@@ -359,12 +349,8 @@ document.addEventListener('DOMContentLoaded', () => {
}
});
// --- 7. STARTUP SEQUENCE (Browser Restore Friendly) ---
// Check what mode the browser remembered
// --- 7. STARTUP SEQUENCE ---
const initialMode = modeSelector.value;
// Force the correct form to show based on that mode
document.querySelectorAll('.input-form').forEach(f => f.classList.remove('active'));
const initialForm = document.getElementById(`form-${initialMode}`);
if (initialForm) {
@@ -372,7 +358,5 @@ document.addEventListener('DOMContentLoaded', () => {
const startField = initialForm.querySelector('input, textarea');
if (startField) startField.focus();
}
// Render whatever data the browser remembered
handleUpdate(true);
});