Ctrl/Cmd+V로 이미지를 선택해 기존 업로드 흐름으로 바로 올릴 수 있게 한다. Co-authored-by: Cursor <cursoragent@cursor.com>
217 lines
6.4 KiB
JavaScript
217 lines
6.4 KiB
JavaScript
(function () {
|
|
function qs(id) { return document.getElementById(id); }
|
|
|
|
function humanSize(bytes) {
|
|
if (!bytes && bytes !== 0) return '';
|
|
var units = ['B', 'KB', 'MB', 'GB'];
|
|
var i = 0;
|
|
var n = bytes;
|
|
while (n >= 1024 && i < units.length - 1) { n /= 1024; i++; }
|
|
return (Math.round(n * 10) / 10) + ' ' + units[i];
|
|
}
|
|
|
|
function setStatus(text) {
|
|
var el = qs('upload-status');
|
|
if (el) el.textContent = text || '';
|
|
}
|
|
|
|
function init() {
|
|
var dropzone = qs('dropzone');
|
|
var fileInput = qs('file-input');
|
|
var previewWrap = qs('upload-preview');
|
|
var previewImg = qs('preview-img');
|
|
var previewMeta = qs('preview-meta');
|
|
var uploadBtn = qs('upload-btn');
|
|
|
|
if (!dropzone || !fileInput || !uploadBtn) return;
|
|
|
|
var selectedFile = null;
|
|
|
|
function showPreview(file) {
|
|
selectedFile = file;
|
|
uploadBtn.disabled = !file;
|
|
setStatus('');
|
|
|
|
if (!file) {
|
|
if (previewWrap) previewWrap.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
if (previewWrap) previewWrap.style.display = 'block';
|
|
if (previewMeta) previewMeta.textContent = file.name + ' · ' + humanSize(file.size);
|
|
|
|
var reader = new FileReader();
|
|
reader.onload = function (e) {
|
|
if (previewImg) previewImg.src = e.target.result;
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
|
|
function isImageFile(file) {
|
|
return file && file.type && file.type.indexOf('image/') === 0;
|
|
}
|
|
|
|
function onFiles(files) {
|
|
if (!files || !files.length) return;
|
|
var f = files[0];
|
|
if (!isImageFile(f)) {
|
|
setStatus('이미지 파일만 업로드 가능합니다.');
|
|
return;
|
|
}
|
|
showPreview(f);
|
|
}
|
|
|
|
function pad2(n) {
|
|
return (n < 10 ? '0' : '') + n;
|
|
}
|
|
|
|
function pasteFilename(mime) {
|
|
var now = new Date();
|
|
var stamp =
|
|
now.getFullYear() +
|
|
pad2(now.getMonth() + 1) +
|
|
pad2(now.getDate()) +
|
|
'_' +
|
|
pad2(now.getHours()) +
|
|
pad2(now.getMinutes()) +
|
|
pad2(now.getSeconds());
|
|
var ext = 'png';
|
|
if (mime === 'image/jpeg') ext = 'jpg';
|
|
else if (mime === 'image/gif') ext = 'gif';
|
|
else if (mime === 'image/webp') ext = 'webp';
|
|
return 'paste_' + stamp + '.' + ext;
|
|
}
|
|
|
|
function fileFromClipboardItem(item) {
|
|
if (!item || typeof item.getAsFile !== 'function') return null;
|
|
var blob = item.getAsFile();
|
|
if (!blob || !isImageFile(blob)) return null;
|
|
var name = blob.name && blob.name !== 'image.png'
|
|
? blob.name
|
|
: pasteFilename(blob.type || 'image/png');
|
|
try {
|
|
return new File([blob], name, { type: blob.type || 'image/png' });
|
|
} catch (e) {
|
|
// Older browsers may not support File constructor
|
|
blob.name = name;
|
|
return blob;
|
|
}
|
|
}
|
|
|
|
function onPaste(e) {
|
|
var target = e.target;
|
|
if (target) {
|
|
var tag = (target.tagName || '').toLowerCase();
|
|
if (tag === 'input' || tag === 'textarea' || target.isContentEditable) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
var clipboard = e.clipboardData || window.clipboardData;
|
|
if (!clipboard) return;
|
|
|
|
var items = clipboard.items;
|
|
if (items && items.length) {
|
|
for (var i = 0; i < items.length; i++) {
|
|
var item = items[i];
|
|
if (!item || !item.type || item.type.indexOf('image/') !== 0) continue;
|
|
var file = fileFromClipboardItem(item);
|
|
if (!file) continue;
|
|
e.preventDefault();
|
|
showPreview(file);
|
|
setStatus('클립보드 이미지 선택됨. 업로드를 눌러주세요.');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Fallback: some browsers expose files directly
|
|
if (clipboard.files && clipboard.files.length) {
|
|
var pasted = clipboard.files[0];
|
|
if (isImageFile(pasted)) {
|
|
e.preventDefault();
|
|
onFiles(clipboard.files);
|
|
setStatus('클립보드 이미지 선택됨. 업로드를 눌러주세요.');
|
|
}
|
|
}
|
|
}
|
|
|
|
dropzone.addEventListener('dragover', function (e) {
|
|
e.preventDefault();
|
|
dropzone.classList.add('dragover');
|
|
});
|
|
dropzone.addEventListener('dragleave', function () {
|
|
dropzone.classList.remove('dragover');
|
|
});
|
|
dropzone.addEventListener('drop', function (e) {
|
|
e.preventDefault();
|
|
dropzone.classList.remove('dragover');
|
|
onFiles(e.dataTransfer.files);
|
|
});
|
|
|
|
fileInput.addEventListener('change', function () {
|
|
onFiles(fileInput.files);
|
|
});
|
|
|
|
document.addEventListener('paste', onPaste);
|
|
|
|
uploadBtn.addEventListener('click', function () {
|
|
if (!selectedFile) return;
|
|
uploadBtn.disabled = true;
|
|
setStatus('업로드 중...');
|
|
|
|
var fd = new FormData();
|
|
fd.append('image', selectedFile);
|
|
|
|
fetch('api/upload_image.php', {
|
|
method: 'POST',
|
|
body: fd,
|
|
credentials: 'same-origin'
|
|
})
|
|
.then(function (r) { return r.json(); })
|
|
.then(function (data) {
|
|
if (!data || !data.ok) {
|
|
throw new Error((data && data.error) ? data.error : '업로드 실패');
|
|
}
|
|
|
|
// Add immediately to current gallery
|
|
var filename = data.filename;
|
|
var thumbHtml = (typeof buildThumbLi === 'function')
|
|
? buildThumbLi(filename)
|
|
: '';
|
|
if (thumbHtml && window.dreamgirlGallery && typeof window.dreamgirlGallery.appendImage === 'function') {
|
|
window.dreamgirlGallery.appendImage(thumbHtml);
|
|
} else if (thumbHtml) {
|
|
// fallback: append to DOM
|
|
var ul = document.querySelector('#thumbs ul.thumbs');
|
|
if (ul) ul.insertAdjacentHTML('beforeend', thumbHtml);
|
|
}
|
|
|
|
// keep in-memory list (doesn't persist; list_images.php handles persistence)
|
|
if (window.DREAMGIRL_IMAGES && window.DREAMGIRL_IMAGES.push) {
|
|
window.DREAMGIRL_IMAGES.push(filename);
|
|
}
|
|
|
|
setStatus('업로드 완료: ' + filename);
|
|
// reset
|
|
selectedFile = null;
|
|
if (fileInput) fileInput.value = '';
|
|
if (previewWrap) previewWrap.style.display = 'none';
|
|
})
|
|
.catch(function (err) {
|
|
setStatus('에러: ' + (err && err.message ? err.message : '업로드 실패'));
|
|
})
|
|
.finally(function () {
|
|
uploadBtn.disabled = false;
|
|
});
|
|
});
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|
|
|
|
|