Files
KantSites/public/assets/media-drop.js
T
kantarciandClaude Opus 5 e8a9dcdf5c Upload PDFs to the library, link them from any link target, show them in a viewer
PDFs go through the same upload field as images, are checked by their content and kept
unchanged in their own table. Every link field can pick one, and a page that links a PDF
opens it in a dialog with the browser's own viewer; touch devices and browsers without a
viewer get a new tab instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 07:56:29 +02:00

52 lines
2.2 KiB
JavaScript
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.
/**
* Dragging images and PDFs onto the upload field, and saying which files are about to go up.
*
* Everything here is an addition. Without this script the field is still a file input with a
* label: clicking it opens the file picker and the form submits the same way. The script never
* uploads by itself - the button stays the moment where something is sent.
*/
const zone = document.querySelector('[data-dropzone]');
const input = zone?.querySelector('input[type="file"]');
const chosen = document.querySelector('[data-chosen]');
if (zone && input && chosen) {
const ACCEPTED = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
const describe = (files, ignored = 0) => {
if (!files.length) {
chosen.textContent = ignored
? `Keine passende Datei dabei. ${ignored} Datei(en) übersprungen – erlaubt sind JPEG, PNG, WebP und PDF.`
: 'Noch keine Datei gewählt.';
return;
}
const names = [...files].map(file => file.name).join(', ');
const size = [...files].reduce((total, file) => total + file.size, 0);
chosen.textContent = `${files.length} Datei(en) gewählt (${(size / 1048576).toFixed(1)} MB): ${names}`
+ (ignored ? ` · ${ignored} Datei(en) übersprungen, erlaubt sind JPEG, PNG, WebP und PDF.` : '');
};
input.addEventListener('change', () => describe(input.files));
// Without preventDefault the browser navigates to the dropped file and the page is gone.
for (const event of ['dragenter', 'dragover']) {
zone.addEventListener(event, dragged => {
dragged.preventDefault();
zone.classList.add('is-dragging');
});
}
for (const event of ['dragleave', 'dragend']) {
zone.addEventListener(event, () => zone.classList.remove('is-dragging'));
}
zone.addEventListener('drop', dropped => {
dropped.preventDefault();
zone.classList.remove('is-dragging');
const files = [...(dropped.dataTransfer?.files ?? [])];
const images = files.filter(file => ACCEPTED.includes(file.type));
// The input is what the form submits, so the dropped files have to end up in it.
const transfer = new DataTransfer();
images.forEach(file => transfer.items.add(file));
input.files = transfer.files;
describe(input.files, files.length - images.length);
});
}