Improve paste-to-upload UX with a modal dialog; drop media file preview in My Projects

This commit is contained in:
2026-07-08 14:27:07 +02:00
parent 0ccbef45a1
commit 8ec6e3fd50
7 changed files with 108 additions and 53 deletions
+19
View File
@@ -120,6 +120,25 @@
</div> </div>
</div> </div>
<div class="modal fade" id="pasteImageModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content bg-dark text-white border border-secondary">
<div class="modal-header border-secondary">
<h5 class="modal-title">Paste Image</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center">
<div id="pasteImageTarget" contenteditable="true" spellcheck="false"
class="border border-secondary rounded p-5 mb-3 text-white-50"
style="outline:none;cursor:text;min-height:120px;display:flex;align-items:center;justify-content:center;">
Click here, then press Ctrl+V to paste your image
</div>
<img id="pasteImageModalPreview" style="display:none;max-width:100%;max-height:220px;border-radius:6px;" />
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.bundle.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.bundle.min.js"></script>
<script src="@Url.Content("~/web_atakanozbancom/assets/js/paste-upload.js")"></script> <script src="@Url.Content("~/web_atakanozbancom/assets/js/paste-upload.js")"></script>
</body> </body>
+4 -5
View File
@@ -19,7 +19,10 @@
<label class="text-white">Current Logo</label><br /> <label class="text-white">Current Logo</label><br />
<img id="logoPreview" src="@Model.existingImage" alt="@Model.TitleEN" style="@(string.IsNullOrWhiteSpace(Model.existingImage) ? "display:none;" : "")width:64px;height:64px;object-fit:contain;background:#fff;border-radius:6px;padding:4px;" /> <img id="logoPreview" src="@Model.existingImage" alt="@Model.TitleEN" style="@(string.IsNullOrWhiteSpace(Model.existingImage) ? "display:none;" : "")width:64px;height:64px;object-fit:contain;background:#fff;border-radius:6px;padding:4px;" />
<input id="logoFile" type="file" name="logoFile" class="form-control bg-dark text-white mt-2" accept="image/*" /> <input id="logoFile" type="file" name="logoFile" class="form-control bg-dark text-white mt-2" accept="image/*" />
<small class="text-muted">Leave empty to keep the current logo. You can also paste (Ctrl+V) an image directly.</small> <button type="button" class="btn btn-outline-light btn-sm mt-2" onclick="PasteImageModal.open('#logoFile', '#logoPreview')">
<i class="fa-solid fa-paste me-1"></i>Paste image
</button>
<small class="text-muted d-block mt-1">Leave empty to keep the current logo.</small>
</div> </div>
<div class="mb-3"> <div class="mb-3">
@@ -56,7 +59,3 @@
<button class="btn btn-success">Save</button> <button class="btn btn-success">Save</button>
} }
<script>
enablePasteUpload('#logoFile', '#logoPreview');
</script>
+4 -4
View File
@@ -100,9 +100,11 @@ else
<!-- FILE UPLOAD --> <!-- FILE UPLOAD -->
<div id="fileWrap" class="mb-2"> <div id="fileWrap" class="mb-2">
<label class="text-white">Upload</label> <label class="text-white">Upload</label>
<img id="mediaFilePreview" style="display:none;max-width:160px;max-height:120px;object-fit:contain;background:#fff;border-radius:6px;padding:4px;" class="mb-2 d-block" />
<input id="mediaFile" type="file" name="mediaFile" class="form-control bg-dark text-white" /> <input id="mediaFile" type="file" name="mediaFile" class="form-control bg-dark text-white" />
<small class="text-muted">Upload image/document files. You can also paste (Ctrl+V) an image directly.</small> <button type="button" class="btn btn-outline-light btn-sm mt-2" onclick="PasteImageModal.open('#mediaFile')">
<i class="fa-solid fa-paste me-1"></i>Paste image
</button>
<small class="text-muted d-block mt-1">Upload image/document files.</small>
</div> </div>
<div class="mb-3"> <div class="mb-3">
@@ -137,7 +139,5 @@ else
sel.addEventListener("change", sync); sel.addEventListener("change", sync);
sync(); sync();
})(); })();
enablePasteUpload('#mediaFile', '#mediaFilePreview');
</script> </script>
+5 -6
View File
@@ -14,9 +14,12 @@
<div class="mb-3"> <div class="mb-3">
<label class="text-white">Logo</label> <label class="text-white">Logo</label>
<img id="logoPreview" style="display:none;width:64px;height:64px;object-fit:contain;background:#fff;border-radius:6px;padding:4px;" class="mb-2" /> <img id="logoPreview" style="display:none;width:64px;height:64px;object-fit:contain;background:#fff;border-radius:6px;padding:4px;" class="mb-2 d-block" />
<input id="logoFile" type="file" name="logoFile" class="form-control bg-dark text-white" accept="image/*" /> <input id="logoFile" type="file" name="logoFile" class="form-control bg-dark text-white" accept="image/*" />
<small class="text-muted">PNG, JPG, WEBP or GIF. You can also paste (Ctrl+V) an image directly.</small> <button type="button" class="btn btn-outline-light btn-sm mt-2" onclick="PasteImageModal.open('#logoFile', '#logoPreview')">
<i class="fa-solid fa-paste me-1"></i>Paste image
</button>
<small class="text-muted d-block mt-1">PNG, JPG, WEBP or GIF.</small>
</div> </div>
<div class="mb-3"> <div class="mb-3">
@@ -54,7 +57,3 @@
<button class="btn btn-success">Save</button> <button class="btn btn-success">Save</button>
} }
<script>
enablePasteUpload('#logoFile', '#logoPreview');
</script>
+5 -4
View File
@@ -100,9 +100,11 @@ else
<!-- FILE UPLOAD --> <!-- FILE UPLOAD -->
<div id="fileWrap" class="mb-2"> <div id="fileWrap" class="mb-2">
<label class="text-white">Upload</label> <label class="text-white">Upload</label>
<img id="mediaFilePreview" style="display:none;max-width:160px;max-height:120px;object-fit:contain;background:#fff;border-radius:6px;padding:4px;" class="mb-2 d-block" />
<input id="mediaFile" type="file" name="mediaFile" class="form-control bg-dark text-white" /> <input id="mediaFile" type="file" name="mediaFile" class="form-control bg-dark text-white" />
<small class="text-muted">Upload image/document files. You can also paste (Ctrl+V) an image directly.</small> <button type="button" class="btn btn-outline-light btn-sm mt-2" onclick="PasteImageModal.open('#mediaFile')">
<i class="fa-solid fa-paste me-1"></i>Paste image
</button>
<small class="text-muted d-block mt-1">Upload image/document files.</small>
</div> </div>
<div class="mb-3"> <div class="mb-3">
@@ -136,5 +138,4 @@ else
sel.addEventListener("change", sync); sel.addEventListener("change", sync);
sync(); sync();
})(); })();
</script>
enablePasteUpload('#mediaFile', '#mediaFilePreview');</script>
+4 -5
View File
@@ -21,7 +21,10 @@
<label class="text-white">New wallpaper image</label> <label class="text-white">New wallpaper image</label>
<img id="wallpaperPreview" style="display:none;max-width:100%;max-height:300px;border-radius:8px;" class="mb-2 d-block" /> <img id="wallpaperPreview" style="display:none;max-width:100%;max-height:300px;border-radius:8px;" class="mb-2 d-block" />
<input id="wallpaperFile" type="file" name="wallpaperFile" class="form-control bg-dark text-white" accept="image/*" /> <input id="wallpaperFile" type="file" name="wallpaperFile" class="form-control bg-dark text-white" accept="image/*" />
<small class="text-muted">PNG, JPG, WEBP or GIF. You can also paste (Ctrl+V) an image directly.</small> <button type="button" class="btn btn-outline-light btn-sm mt-2" onclick="PasteImageModal.open('#wallpaperFile', '#wallpaperPreview')">
<i class="fa-solid fa-paste me-1"></i>Paste image
</button>
<small class="text-muted d-block mt-1">PNG, JPG, WEBP or GIF.</small>
</div> </div>
<button class="btn btn-success">Upload New Wallpaper</button> <button class="btn btn-success">Upload New Wallpaper</button>
@@ -32,7 +35,3 @@
@Html.AntiForgeryToken() @Html.AntiForgeryToken()
<button type="submit" class="btn btn-secondary mt-2">Reset to Default</button> <button type="submit" class="btn btn-secondary mt-2">Reset to Default</button>
} }
<script>
enablePasteUpload('#wallpaperFile', '#wallpaperPreview');
</script>
+48 -10
View File
@@ -1,8 +1,24 @@
function enablePasteUpload(inputSelector, previewSelector) { var PasteImageModal = (function () {
var input = document.querySelector(inputSelector); var bsModal, targetEl, previewEl, defaultText;
if (!input) return; var currentInputSelector, currentPreviewSelector;
document.addEventListener('paste', function (e) { function init() {
var modalEl = document.getElementById('pasteImageModal');
if (!modalEl || typeof bootstrap === 'undefined') return false;
targetEl = document.getElementById('pasteImageTarget');
previewEl = document.getElementById('pasteImageModalPreview');
defaultText = targetEl.textContent;
bsModal = new bootstrap.Modal(modalEl);
modalEl.addEventListener('shown.bs.modal', function () {
targetEl.textContent = defaultText;
previewEl.style.display = 'none';
previewEl.removeAttribute('src');
targetEl.focus();
});
targetEl.addEventListener('paste', function (e) {
var clipboard = e.clipboardData || window.clipboardData; var clipboard = e.clipboardData || window.clipboardData;
var items = clipboard ? clipboard.items : null; var items = clipboard ? clipboard.items : null;
if (!items) return; if (!items) return;
@@ -10,28 +26,50 @@ function enablePasteUpload(inputSelector, previewSelector) {
for (var i = 0; i < items.length; i++) { for (var i = 0; i < items.length; i++) {
var item = items[i]; var item = items[i];
if (item.kind === 'file' && item.type.indexOf('image/') === 0) { if (item.kind === 'file' && item.type.indexOf('image/') === 0) {
e.preventDefault();
var blob = item.getAsFile(); var blob = item.getAsFile();
if (!blob) continue; if (!blob) continue;
var ext = (blob.type.split('/')[1] || 'png').toLowerCase(); var ext = (blob.type.split('/')[1] || 'png').toLowerCase();
var pastedFile = new File([blob], 'pasted-image-' + Date.now() + '.' + ext, { type: blob.type }); var pastedFile = new File([blob], 'pasted-image-' + Date.now() + '.' + ext, { type: blob.type });
var input = document.querySelector(currentInputSelector);
if (input) {
var dt = new DataTransfer(); var dt = new DataTransfer();
dt.items.add(pastedFile); dt.items.add(pastedFile);
input.files = dt.files; input.files = dt.files;
input.dispatchEvent(new Event('change', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true }));
}
if (previewSelector) { var url = URL.createObjectURL(pastedFile);
var preview = document.querySelector(previewSelector); previewEl.src = url;
if (preview) { previewEl.style.display = '';
preview.src = URL.createObjectURL(pastedFile); targetEl.textContent = 'Image pasted!';
preview.style.display = '';
if (currentPreviewSelector) {
var extPreview = document.querySelector(currentPreviewSelector);
if (extPreview) {
extPreview.src = url;
extPreview.style.display = '';
} }
} }
e.preventDefault(); setTimeout(function () { bsModal.hide(); }, 400);
break; break;
} }
} }
}); });
return true;
} }
function open(inputSelector, previewSelector) {
if (!bsModal && !init()) return;
currentInputSelector = inputSelector;
currentPreviewSelector = previewSelector || null;
bsModal.show();
}
return { open: open };
})();