fix: cropper mime bug + loadSiteIdentity crash + logo|name header
1. applyCrop() — mime variable was declared INSIDE toBlob callback but used as an argument to toBlob() (outer scope) → ReferenceError. Fix: declare _mime, _quality, _ext BEFORE out.toBlob() call. 2. loadSiteIdentity() — crashed when identity section had no rows (data was null/non-array). Fix: safe Array.isArray guard + catch. 3. Header logo: show logo image + | + site name side by side when logo is configured (was showing one OR the other). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1375,9 +1375,9 @@ async function deleteReq(id){if(!confirm('حذف؟'))return;await api(`/api/heal
|
||||
// ── Comments ──────────────────────────────────────────────────────────────────
|
||||
// ── Site Identity (logo / favicon) ────────────────────────────────────────────
|
||||
async function loadSiteIdentity() {
|
||||
const data = await api('/api/settings/identity') || [];
|
||||
const data = await api('/api/settings/identity').catch(()=>[]) || [];
|
||||
const vals = {};
|
||||
data.forEach(s => vals[s.key] = s.value);
|
||||
(Array.isArray(data) ? data : []).forEach(s => vals[s.key] = s.value);
|
||||
// Set hidden inputs
|
||||
document.getElementById('si-logo').value = vals.logo || '';
|
||||
document.getElementById('si-favicon').value = vals.favicon || '';
|
||||
@@ -1823,8 +1823,13 @@ async function applyCrop() {
|
||||
const out = document.createElement('canvas');
|
||||
out.width = Math.round(sw); out.height = Math.round(sh);
|
||||
out.getContext('2d').drawImage(cropper.img, sx, sy, sw, sh, 0, 0, out.width, out.height);
|
||||
// Capture targets BEFORE closing (closeCropper doesn't clear them, but be safe)
|
||||
const _inputId = cropper.inputId, _previewId = cropper.previewId;
|
||||
// Capture targets and mime type BEFORE the async callback
|
||||
const _inputId = cropper.inputId;
|
||||
const _previewId = cropper.previewId;
|
||||
const _mime = cropper.mimeType || 'image/jpeg';
|
||||
const _quality = (_mime === 'image/jpeg' || _mime === 'image/webp') ? 0.92 : undefined;
|
||||
const _ext = _mime.split('/')[1].replace('jpeg','jpg').replace('vnd.microsoft.icon','ico').replace('x-icon','ico').replace('svg+xml','svg');
|
||||
|
||||
out.toBlob(async blob => {
|
||||
closeCropper();
|
||||
const inputId = _inputId, previewId = _previewId;
|
||||
@@ -1834,8 +1839,7 @@ async function applyCrop() {
|
||||
btn.disabled = true;
|
||||
try {
|
||||
const fd = new FormData();
|
||||
const ext = _inputId && cropper.mimeType ? cropper.mimeType.split('/')[1].replace('jpeg','jpg') : 'jpg';
|
||||
fd.append('file', new File([blob], `crop.${ext}`, {type: cropper.mimeType || 'image/jpeg'}));
|
||||
fd.append('file', new File([blob], `crop.${_ext}`, {type: _mime}));
|
||||
const r = await fetch('/api/upload', {method:'POST', headers:{'Authorization':`Bearer ${token}`}, body:fd});
|
||||
if (!r.ok) throw new Error(await r.text());
|
||||
const { url } = await r.json();
|
||||
@@ -1844,10 +1848,7 @@ async function applyCrop() {
|
||||
toast('تصویر با موفقیت آپلود شد ✓');
|
||||
} catch(e) { toast('خطا در آپلود: '+e.message,'error'); }
|
||||
finally { btn.innerHTML=orig; btn.disabled=false; }
|
||||
// Use original mime type; only pass quality for lossy formats
|
||||
const mime = cropper.mimeType || 'image/jpeg';
|
||||
const quality = (mime === 'image/jpeg' || mime === 'image/webp') ? 0.92 : undefined;
|
||||
}, mime, quality);
|
||||
}, _mime, _quality);
|
||||
}
|
||||
|
||||
async function uploadImage(inputId, previewId) {
|
||||
|
||||
Reference in New Issue
Block a user