fix(index): paste fills only project files, photo stays webcam-only
- pasted images/files always go to "Файлы проекта", never to the entry photo
- drop the photo paste hint and the capturedName plumbing: the entry photo is
captured from the camera only (submit still requires it)
- keep paste naming ("Вставка <date>.<ext>") and server-mirrored limits
This commit is contained in:
@@ -113,7 +113,6 @@ nav a:hover{color:var(--text)}
|
|||||||
<div class="photo-btns">
|
<div class="photo-btns">
|
||||||
<button type="button" class="cam" id="openCamBtn">Камера</button>
|
<button type="button" class="cam" id="openCamBtn">Камера</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="paste-hint" id="photoPasteHint">Ctrl+V — вставить фото из буфера</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="files-card">
|
<div class="files-card">
|
||||||
<div class="files-head">
|
<div class="files-head">
|
||||||
|
|||||||
+4
-21
@@ -13,9 +13,7 @@ const toast = document.getElementById('toast');
|
|||||||
const camVideo = document.getElementById('camVideo');
|
const camVideo = document.getElementById('camVideo');
|
||||||
const camCanvas = document.getElementById('camCanvas');
|
const camCanvas = document.getElementById('camCanvas');
|
||||||
const camModal = document.getElementById('camModal');
|
const camModal = document.getElementById('camModal');
|
||||||
const photoPasteHint = document.getElementById('photoPasteHint');
|
|
||||||
let capturedBlob = null;
|
let capturedBlob = null;
|
||||||
let capturedName = 'photo.jpg';
|
|
||||||
let stream = null;
|
let stream = null;
|
||||||
const descInput = document.getElementById('descInput');
|
const descInput = document.getElementById('descInput');
|
||||||
const filesInput = document.getElementById('filesInput');
|
const filesInput = document.getElementById('filesInput');
|
||||||
@@ -124,7 +122,6 @@ const MAX_FILES = 10;
|
|||||||
const MAX_FILE_BYTES = 10 * 1024 * 1024;
|
const MAX_FILE_BYTES = 10 * 1024 * 1024;
|
||||||
const MAX_TOTAL_BYTES = 30 * 1024 * 1024;
|
const MAX_TOTAL_BYTES = 30 * 1024 * 1024;
|
||||||
const BLOCKED_FILE_EXT = /\.(?:html?|js|mjs|cjs|svg|xml|json|map|wasm|php\d?|phtml|asp|aspx|jsp|sh|bat|cmd|cgi|exe|dll|com|msi|scr|hta|vbs|py|r|rb|htaccess)$/i;
|
const BLOCKED_FILE_EXT = /\.(?:html?|js|mjs|cjs|svg|xml|json|map|wasm|php\d?|phtml|asp|aspx|jsp|sh|bat|cmd|cgi|exe|dll|com|msi|scr|hta|vbs|py|r|rb|htaccess)$/i;
|
||||||
const IMAGE_FILE_EXT = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.avif', '.ico', '.heic', '.heif', '.jfif']);
|
|
||||||
const MIME_EXT = {
|
const MIME_EXT = {
|
||||||
'image/png': '.png', 'image/jpeg': '.jpg', 'image/jpg': '.jpg', 'image/gif': '.gif', 'image/webp': '.webp',
|
'image/png': '.png', 'image/jpeg': '.jpg', 'image/jpg': '.jpg', 'image/gif': '.gif', 'image/webp': '.webp',
|
||||||
'image/bmp': '.bmp', 'image/avif': '.avif', 'image/heic': '.heic', 'image/heif': '.heif', 'image/svg+xml': '.svg',
|
'image/bmp': '.bmp', 'image/avif': '.avif', 'image/heic': '.heic', 'image/heif': '.heif', 'image/svg+xml': '.svg',
|
||||||
@@ -208,31 +205,21 @@ document.addEventListener('paste', (e) => {
|
|||||||
if (!pasted.length && clip.files && clip.files.length) pasted.push(...Array.from(clip.files));
|
if (!pasted.length && clip.files && clip.files.length) pasted.push(...Array.from(clip.files));
|
||||||
if (!pasted.length) return;
|
if (!pasted.length) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let photoSet = false;
|
|
||||||
let filesAdded = 0;
|
let filesAdded = 0;
|
||||||
const skipped = [];
|
const skipped = [];
|
||||||
for (const raw of pasted) {
|
for (const raw of pasted) {
|
||||||
const name = pasteFileName(raw);
|
const name = pasteFileName(raw);
|
||||||
const file = raw.name === name ? raw : new File([raw], name, { type: raw.type || 'application/octet-stream', lastModified: raw.lastModified });
|
const file = raw.name === name ? raw : new File([raw], name, { type: raw.type || 'application/octet-stream', lastModified: raw.lastModified });
|
||||||
if (!capturedBlob && IMAGE_FILE_EXT.has(extFromFile(file))) {
|
|
||||||
capturedBlob = file;
|
|
||||||
capturedName = name;
|
|
||||||
showPreview(URL.createObjectURL(file));
|
|
||||||
photoSet = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const res = addFiles([file]);
|
const res = addFiles([file]);
|
||||||
filesAdded += res.added.length;
|
filesAdded += res.added.length;
|
||||||
skipped.push(...res.skipped);
|
skipped.push(...res.skipped);
|
||||||
}
|
}
|
||||||
const parts = [];
|
if (!filesAdded) {
|
||||||
if (photoSet) parts.push('Фото вставлено из буфера');
|
|
||||||
if (filesAdded) parts.push(filesAdded === 1 ? 'Файл добавлен' : `Файлов добавлено: ${filesAdded}`);
|
|
||||||
if (!parts.length) {
|
|
||||||
if (skipped.length) notify(skipped[0], true);
|
if (skipped.length) notify(skipped[0], true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
notify(parts.join('. ') + (skipped.length ? '. ' + skipped[0] : ''), skipped.length > 0);
|
const summary = filesAdded === 1 ? 'Файл добавлен' : `Файлов добавлено: ${filesAdded}`;
|
||||||
|
notify(summary + (skipped.length ? '. ' + skipped[0] : ''), skipped.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
const params = new URLSearchParams(location.search);
|
const params = new URLSearchParams(location.search);
|
||||||
@@ -339,16 +326,13 @@ function showPreview(src) {
|
|||||||
preview.src = src;
|
preview.src = src;
|
||||||
preview.classList.add('has-photo');
|
preview.classList.add('has-photo');
|
||||||
removePhotoBtn.classList.add('show');
|
removePhotoBtn.classList.add('show');
|
||||||
photoPasteHint.style.display = 'none';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePhoto() {
|
function removePhoto() {
|
||||||
preview.src = placeholderSrc;
|
preview.src = placeholderSrc;
|
||||||
preview.classList.remove('has-photo');
|
preview.classList.remove('has-photo');
|
||||||
removePhotoBtn.classList.remove('show');
|
removePhotoBtn.classList.remove('show');
|
||||||
photoPasteHint.style.display = '';
|
|
||||||
capturedBlob = null;
|
capturedBlob = null;
|
||||||
capturedName = 'photo.jpg';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openCam() {
|
async function openCam() {
|
||||||
@@ -375,7 +359,6 @@ function capture() {
|
|||||||
ctx.drawImage(camVideo, 0, 0);
|
ctx.drawImage(camVideo, 0, 0);
|
||||||
camCanvas.toBlob(blob => {
|
camCanvas.toBlob(blob => {
|
||||||
capturedBlob = blob;
|
capturedBlob = blob;
|
||||||
capturedName = 'photo.jpg';
|
|
||||||
showPreview(URL.createObjectURL(blob));
|
showPreview(URL.createObjectURL(blob));
|
||||||
closeCam();
|
closeCam();
|
||||||
}, 'image/jpeg', captureQuality);
|
}, 'image/jpeg', captureQuality);
|
||||||
@@ -404,7 +387,7 @@ form.addEventListener('submit', async (e) => {
|
|||||||
btn.textContent = 'Отправка...';
|
btn.textContent = 'Отправка...';
|
||||||
|
|
||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append('photo', capturedBlob, capturedName);
|
fd.append('photo', capturedBlob, 'photo.jpg');
|
||||||
selectedFiles.forEach(f => fd.append('files', f, f.name));
|
selectedFiles.forEach(f => fd.append('files', f, f.name));
|
||||||
fd.append('student_name', studentName || document.getElementById('nameInput').value);
|
fd.append('student_name', studentName || document.getElementById('nameInput').value);
|
||||||
fd.append('group_id', groupInput.value);
|
fd.append('group_id', groupInput.value);
|
||||||
|
|||||||
Reference in New Issue
Block a user