(() => { "use strict"; const modeEl = document.getElementById("qr-mode"); const modeTextWrap = document.getElementById("mode-text"); const modeWifiWrap = document.getElementById("mode-wifi"); const textEl = document.getElementById("qr-text"); const wifiSsidEl = document.getElementById("wifi-ssid"); const wifiEncryptionEl = document.getElementById("wifi-encryption"); const wifiPasswordEl = document.getElementById("wifi-password"); const wifiPasswordField = document.getElementById("wifi-password-field"); const wifiHiddenEl = document.getElementById("wifi-hidden"); const cellSizeEl = document.getElementById("qr-cell-size"); const correctionEl = document.getElementById("qr-correction"); const fgColorEl = document.getElementById("qr-fg-color"); const bgColorEl = document.getElementById("qr-bg-color"); const logoInputEl = document.getElementById("qr-logo-input"); const logoClearBtn = document.getElementById("qr-logo-clear"); const generateBtn = document.getElementById("generate-btn"); const downloadBtn = document.getElementById("download-btn"); const canvas = document.getElementById("qr-canvas"); const statusEl = document.getElementById("qr-status"); const ctx = canvas.getContext("2d"); let logoImage = null; function readLogoFile(file) { if (!file) return; const reader = new FileReader(); reader.onload = () => { const img = new Image(); img.onload = () => { logoImage = img; render(); }; img.src = reader.result; }; reader.readAsDataURL(file); } logoInputEl.addEventListener("change", (e) => { readLogoFile(e.target.files[0]); }); logoClearBtn.addEventListener("click", () => { logoImage = null; logoInputEl.value = ""; render(); }); function escapeWifiField(value) { return String(value).replace(/([\\;,":])/g, "\\$1"); } function buildWifiPayload() { const ssid = wifiSsidEl.value; const encryption = wifiEncryptionEl.value; const password = wifiPasswordEl.value; const hidden = wifiHiddenEl.checked; if (!ssid) return ""; let payload = `WIFI:T:${encryption};S:${escapeWifiField(ssid)};`; if (encryption !== "nopass" && password) { payload += `P:${escapeWifiField(password)};`; } payload += `H:${hidden ? "true" : "false"};;`; return payload; } function updateModeVisibility() { const isWifi = modeEl.value === "wifi"; modeTextWrap.style.display = isWifi ? "none" : "block"; modeWifiWrap.style.display = isWifi ? "block" : "none"; wifiPasswordField.style.display = wifiEncryptionEl.value === "nopass" ? "none" : "block"; } modeEl.addEventListener("change", () => { updateModeVisibility(); render(); }); wifiEncryptionEl.addEventListener("change", updateModeVisibility); [wifiSsidEl, wifiEncryptionEl, wifiPasswordEl, wifiHiddenEl].forEach((el) => { el.addEventListener("input", render); el.addEventListener("change", render); }); function render() { const isWifi = modeEl.value === "wifi"; const text = isWifi ? buildWifiPayload() : textEl.value; statusEl.classList.remove("error"); if (!text) { ctx.clearRect(0, 0, canvas.width, canvas.height); canvas.width = 280; canvas.height = 280; statusEl.textContent = isWifi ? "Renseignez au moins le nom du réseau (SSID) pour générer le QR code." : "Saisissez un texte ou une URL pour générer le QR code."; return; } const cellSize = parseInt(cellSizeEl.value, 10) || 8; const requestedLevel = correctionEl.value; const level = logoImage ? "H" : requestedLevel; const fgColor = fgColorEl.value || "#000000"; const bgColor = bgColorEl.value || "#ffffff"; const margin = 4; // modules try { const qr = qrcode(0, level); qr.addData(text); qr.make(); const moduleCount = qr.getModuleCount(); const size = (moduleCount + margin * 2) * cellSize; canvas.width = size; canvas.height = size; ctx.imageSmoothingEnabled = false; ctx.fillStyle = bgColor; ctx.fillRect(0, 0, size, size); ctx.fillStyle = fgColor; for (let row = 0; row < moduleCount; row++) { for (let col = 0; col < moduleCount; col++) { if (qr.isDark(row, col)) { ctx.fillRect((col + margin) * cellSize, (row + margin) * cellSize, cellSize, cellSize); } } } if (logoImage) { const logoSize = size * 0.22; const pad = logoSize * 0.14; const x = (size - logoSize) / 2; const y = (size - logoSize) / 2; ctx.fillStyle = bgColor; ctx.fillRect(x - pad, y - pad, logoSize + pad * 2, logoSize + pad * 2); ctx.imageSmoothingEnabled = true; ctx.drawImage(logoImage, x, y, logoSize, logoSize); } statusEl.textContent = logoImage ? `QR code généré (correction ${level}, forcée par le logo).` : `QR code généré (correction ${level}).`; } catch (err) { statusEl.textContent = "Erreur : " + (err.message || "contenu trop long pour être encodé."); statusEl.classList.add("error"); } } function downloadPng() { canvas.toBlob((blob) => { if (!blob) return; const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "qrcode.png"; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }, "image/png"); } [textEl, cellSizeEl, correctionEl, fgColorEl, bgColorEl].forEach((el) => { el.addEventListener("input", render); }); generateBtn.addEventListener("click", render); downloadBtn.addEventListener("click", downloadPng); updateModeVisibility(); render(); })();