Принудительное скачивание QR из lightbox как server-user.png

Кнопка больше не открывает PNG во вкладке: blob/canvas download
с именем <сервер>-<пользователь>.png.
This commit is contained in:
2026-07-23 10:23:16 +03:00
parent 78f4d05ceb
commit e486e1df86
2 changed files with 136 additions and 10 deletions
@@ -759,7 +759,7 @@
</div> </div>
<p class="lightbox-caption" id="lightbox-caption"></p> <p class="lightbox-caption" id="lightbox-caption"></p>
<div class="lightbox-actions"> <div class="lightbox-actions">
<a class="lightbox-download" id="lightbox-download" href="#" download> <a class="lightbox-download" id="lightbox-download" href="#" download role="button">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Скачать QR Скачать QR
</a> </a>
@@ -825,14 +825,75 @@
var caption = document.getElementById('lightbox-caption'); var caption = document.getElementById('lightbox-caption');
var closeBtn = document.getElementById('lightbox-close'); var closeBtn = document.getElementById('lightbox-close');
var downloadBtn = document.getElementById('lightbox-download'); var downloadBtn = document.getElementById('lightbox-download');
var downloadSrc = '';
function triggerFileDownload(blob, filename) {
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = filename;
a.rel = 'noopener';
document.body.appendChild(a);
a.click();
a.remove();
setTimeout(function () { URL.revokeObjectURL(url); }, 1500);
}
function downloadQrImage(e) {
e.preventDefault();
e.stopPropagation();
var filename = downloadBtn.getAttribute('data-filename') || downloadBtn.getAttribute('download') || 'qr.png';
var src = downloadSrc || img.currentSrc || img.src;
function fromCanvas() {
try {
if (!img.complete || !img.naturalWidth) return false;
var canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext('2d').drawImage(img, 0, 0);
canvas.toBlob(function (blob) {
if (blob) triggerFileDownload(blob, filename);
}, 'image/png');
return true;
} catch (err) {
return false;
}
}
if (src) {
fetch(src)
.then(function (res) {
if (!res.ok) throw new Error('fetch failed');
return res.blob();
})
.then(function (blob) { triggerFileDownload(blob, filename); })
.catch(function () {
if (!fromCanvas()) {
var a = document.createElement('a');
a.href = src;
a.download = filename;
a.rel = 'noopener';
document.body.appendChild(a);
a.click();
a.remove();
}
});
} else {
fromCanvas();
}
}
function openLightbox(src, text, alt, filename) { function openLightbox(src, text, alt, filename) {
var safeName = filename || 'qr.png';
img.src = src; img.src = src;
img.alt = alt || text || 'QR'; img.alt = alt || text || 'QR';
caption.textContent = text || ''; caption.textContent = text || '';
downloadBtn.href = src; downloadSrc = src;
downloadBtn.setAttribute('download', filename || 'qr.png'); downloadBtn.href = '#';
downloadBtn.setAttribute('aria-label', 'Скачать ' + (filename || 'qr.png')); downloadBtn.setAttribute('download', safeName);
downloadBtn.setAttribute('data-filename', safeName);
downloadBtn.setAttribute('aria-label', 'Скачать ' + safeName);
box.classList.add('open'); box.classList.add('open');
box.setAttribute('aria-hidden', 'false'); box.setAttribute('aria-hidden', 'false');
document.body.classList.add('lightbox-open'); document.body.classList.add('lightbox-open');
@@ -844,7 +905,8 @@
box.setAttribute('aria-hidden', 'true'); box.setAttribute('aria-hidden', 'true');
document.body.classList.remove('lightbox-open'); document.body.classList.remove('lightbox-open');
img.removeAttribute('src'); img.removeAttribute('src');
downloadBtn.removeAttribute('href'); downloadSrc = '';
downloadBtn.removeAttribute('data-filename');
} }
document.querySelectorAll('[data-lightbox-src]').forEach(function (el) { document.querySelectorAll('[data-lightbox-src]').forEach(function (el) {
@@ -865,6 +927,7 @@
}); });
}); });
downloadBtn.addEventListener('click', downloadQrImage);
closeBtn.addEventListener('click', closeLightbox); closeBtn.addEventListener('click', closeLightbox);
box.addEventListener('click', function (e) { box.addEventListener('click', function (e) {
if (e.target === box) closeLightbox(); if (e.target === box) closeLightbox();
+68 -5
View File
@@ -463,7 +463,7 @@
</div> </div>
<p class="lightbox-caption" id="lightbox-caption"></p> <p class="lightbox-caption" id="lightbox-caption"></p>
<div class="lightbox-actions"> <div class="lightbox-actions">
<a class="lightbox-download" id="lightbox-download" href="#" download> <a class="lightbox-download" id="lightbox-download" href="#" download role="button">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Скачать QR Скачать QR
</a> </a>
@@ -502,14 +502,75 @@
var caption = document.getElementById('lightbox-caption'); var caption = document.getElementById('lightbox-caption');
var closeBtn = document.getElementById('lightbox-close'); var closeBtn = document.getElementById('lightbox-close');
var downloadBtn = document.getElementById('lightbox-download'); var downloadBtn = document.getElementById('lightbox-download');
var downloadSrc = '';
function triggerFileDownload(blob, filename) {
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = filename;
a.rel = 'noopener';
document.body.appendChild(a);
a.click();
a.remove();
setTimeout(function () { URL.revokeObjectURL(url); }, 1500);
}
function downloadQrImage(e) {
e.preventDefault();
e.stopPropagation();
var filename = downloadBtn.getAttribute('data-filename') || downloadBtn.getAttribute('download') || 'qr.png';
var src = downloadSrc || img.currentSrc || img.src;
function fromCanvas() {
try {
if (!img.complete || !img.naturalWidth) return false;
var canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext('2d').drawImage(img, 0, 0);
canvas.toBlob(function (blob) {
if (blob) triggerFileDownload(blob, filename);
}, 'image/png');
return true;
} catch (err) {
return false;
}
}
if (src) {
fetch(src)
.then(function (res) {
if (!res.ok) throw new Error('fetch failed');
return res.blob();
})
.then(function (blob) { triggerFileDownload(blob, filename); })
.catch(function () {
if (!fromCanvas()) {
var a = document.createElement('a');
a.href = src;
a.download = filename;
a.rel = 'noopener';
document.body.appendChild(a);
a.click();
a.remove();
}
});
} else {
fromCanvas();
}
}
function openLightbox(src, text, alt, filename) { function openLightbox(src, text, alt, filename) {
var safeName = filename || 'qr.png';
img.src = src; img.src = src;
img.alt = alt || text || 'QR'; img.alt = alt || text || 'QR';
caption.textContent = text || ''; caption.textContent = text || '';
downloadBtn.href = src; downloadSrc = src;
downloadBtn.setAttribute('download', filename || 'qr.png'); downloadBtn.href = '#';
downloadBtn.setAttribute('aria-label', 'Скачать ' + (filename || 'qr.png')); downloadBtn.setAttribute('download', safeName);
downloadBtn.setAttribute('data-filename', safeName);
downloadBtn.setAttribute('aria-label', 'Скачать ' + safeName);
box.classList.add('open'); box.classList.add('open');
box.setAttribute('aria-hidden', 'false'); box.setAttribute('aria-hidden', 'false');
document.body.classList.add('lightbox-open'); document.body.classList.add('lightbox-open');
@@ -521,7 +582,8 @@
box.setAttribute('aria-hidden', 'true'); box.setAttribute('aria-hidden', 'true');
document.body.classList.remove('lightbox-open'); document.body.classList.remove('lightbox-open');
img.removeAttribute('src'); img.removeAttribute('src');
downloadBtn.removeAttribute('href'); downloadSrc = '';
downloadBtn.removeAttribute('data-filename');
} }
document.querySelectorAll('[data-lightbox-src]').forEach(function (el) { document.querySelectorAll('[data-lightbox-src]').forEach(function (el) {
@@ -542,6 +604,7 @@
}); });
}); });
downloadBtn.addEventListener('click', downloadQrImage);
closeBtn.addEventListener('click', closeLightbox); closeBtn.addEventListener('click', closeLightbox);
box.addEventListener('click', function (e) { box.addEventListener('click', function (e) {
if (e.target === box) closeLightbox(); if (e.target === box) closeLightbox();