Support Image-Upload and Paste-from-Clipboard

This commit is contained in:
2025-09-15 09:48:26 +02:00
parent 216110992f
commit 8daa183885
5 changed files with 846 additions and 219 deletions

View File

@@ -2,16 +2,24 @@
(function () {
"use strict";
// Sort direkt submitten
const sortSel = document.getElementById("sortby");
// ===== Helper =====
function $(sel, root) {
return (root || document).querySelector(sel);
}
function $all(sel, root) {
return Array.from((root || document).querySelectorAll(sel));
}
// ===== Sort direkt submitten =====
const sortSel = $("#sortby");
if (sortSel && sortSel.form) {
sortSel.addEventListener("change", function () {
this.form.submit();
});
}
// Reservation Modal
const reservationModal = document.getElementById("reservationModal");
// ===== Reservation Modal =====
const reservationModal = $("#reservationModal");
if (reservationModal) {
reservationModal.addEventListener("show.bs.modal", function (ev) {
const btn = ev.relatedTarget;
@@ -19,13 +27,12 @@
const wishid = btn.getAttribute("data-wishid");
const reserved = btn.getAttribute("data-reserved");
reservationModal.querySelector("#modal-wishid").value = wishid || "";
reservationModal.querySelector("#modal-reservedstat").value =
reserved || "";
$("#modal-wishid", reservationModal).value = wishid || "";
$("#modal-reservedstat", reservationModal).value = reserved || "";
const submitBtn = reservationModal.querySelector("#reservation-submit");
const titleEl = reservationModal.querySelector("#reservationModalLabel");
const infoEl = reservationModal.querySelector("#ReservationInfoText");
const submitBtn = $("#reservation-submit", reservationModal);
const titleEl = $("#reservationModalLabel", reservationModal);
const infoEl = $("#ReservationInfoText", reservationModal);
if (reserved === "1") {
submitBtn.textContent = "Reservierung aufheben";
@@ -39,8 +46,8 @@
});
}
// Delete Modal
const deleteModal = document.getElementById("deleteModal");
// ===== Delete Modal =====
const deleteModal = $("#deleteModal");
if (deleteModal) {
deleteModal.addEventListener("show.bs.modal", function (ev) {
const btn = ev.relatedTarget;
@@ -51,7 +58,6 @@
: "";
const wishid = btn.getAttribute("data-wishid") || "";
// robust: suche entweder #DelWhishID ODER #WhishID
const idInput = deleteModal.querySelector(
'#DelWhishID, #WhishID, input[name="WhishID"]'
);
@@ -64,8 +70,8 @@
});
}
// Push Prio Modal
const prioModal = document.getElementById("pushprioModal");
// ===== Push Prio Modal =====
const prioModal = $("#pushprioModal");
if (prioModal) {
prioModal.addEventListener("show.bs.modal", function (ev) {
const btn = ev.relatedTarget;
@@ -88,28 +94,118 @@
});
}
// Add/Edit Item Modal
const itemModal = document.getElementById("itemModal");
// ===== Add/Edit Item Modal =====
const itemModal = $("#itemModal");
let _currentPreviewObjectUrl = null;
function revokePreviewUrl() {
if (_currentPreviewObjectUrl) {
try {
URL.revokeObjectURL(_currentPreviewObjectUrl);
} catch (e) {}
_currentPreviewObjectUrl = null;
}
}
if (itemModal) {
itemModal.addEventListener("show.bs.modal", function (ev) {
const btn = ev.relatedTarget;
if (!btn) return;
const mode = btn.getAttribute("data-mode") || "add";
const titleEl = itemModal.querySelector("#itemModalTitle");
const actionEl = itemModal.querySelector("#ItemAction");
const submitEl = itemModal.querySelector("#ItemSubmitBtn");
const removeWrap = itemModal.querySelector("#RemoveImageWrap");
const removeChk = itemModal.querySelector("#RemoveImage");
const titleEl = $("#itemModalTitle", itemModal);
const actionEl = $("#ItemAction", itemModal);
const submitEl = $("#ItemSubmitBtn", itemModal);
const removeWrap = $("#RemoveImageWrap", itemModal);
const removeChk = $("#RemoveImage", itemModal);
// Felder
const fTitle = itemModal.querySelector("#ItemTitle");
const fDesc = itemModal.querySelector("#ItemDescription");
const fPrice = itemModal.querySelector("#ItemPrice");
const fLink = itemModal.querySelector("#ItemLink");
const fImg = itemModal.querySelector("#ItemImage");
const fId = itemModal.querySelector("#WhishID");
const fQty = itemModal.querySelector("#ItemQty"); // <-- NEU
const fTitle = $("#ItemTitle", itemModal);
const fDesc = $("#ItemDescription", itemModal);
const fPrice = $("#ItemPrice", itemModal);
const fLink = $("#ItemLink", itemModal);
const fId = $("#WhishID", itemModal);
const fQty = $("#ItemQty", itemModal);
// Bild-Felder
const fImgUrl = $("#ItemImageUrl", itemModal);
const fImgFile = $("#ItemImageFile", itemModal);
const pasteZone = $("#PasteZone", itemModal);
const pasteVal = $("#ItemImagePaste", itemModal);
const pasteName = $("#ItemImagePasteName", itemModal);
const prevWrap = $("#ImgPreviewWrap", itemModal);
const prevImg = $("#ImgPreview", itemModal);
const pasteActivator = $("#PasteActivator", itemModal);
// Preview-Styling erzwingen (falls keine CSS-Regel vorhanden)
if (prevWrap) {
prevWrap.style.maxHeight = "240px";
prevWrap.style.overflow = "hidden";
prevWrap.style.border = "1px solid rgba(0,0,0,.1)";
prevWrap.style.borderRadius = ".5rem";
prevWrap.style.padding = ".5rem";
prevWrap.style.background = "#fff";
}
if (prevImg) {
prevImg.style.maxWidth = "100%";
prevImg.style.maxHeight = "220px";
prevImg.style.objectFit = "contain";
prevImg.classList.add("img-fluid", "border", "rounded", "w-100");
}
function showPreview(src) {
revokePreviewUrl();
if (!prevWrap || !prevImg) return;
if (!src) {
prevWrap.style.display = "none";
prevImg.removeAttribute("src");
return;
}
prevImg.src = src;
prevWrap.style.display = "block";
if (src.startsWith("blob:")) _currentPreviewObjectUrl = src;
}
function clearUrl() {
if (fImgUrl) fImgUrl.value = "";
}
function clearFile() {
if (fImgFile) fImgFile.value = "";
}
function clearPaste() {
if (pasteVal) pasteVal.value = "";
if (pasteName) pasteName.value = "clipboard.png";
if (pasteZone) {
pasteZone.innerHTML = "";
pasteZone.setAttribute("data-ph-active", "1");
}
}
function clearPreviewAndInputs() {
showPreview("");
clearUrl();
clearFile();
clearPaste();
}
function focusPasteCatcher() {
if (!pasteZone) return;
// kurz sichtbar machen, fokus holen, dann wieder verstecken
pasteZone.classList.remove("visually-hidden");
pasteZone.focus();
// cursor ans ende
const sel = window.getSelection();
if (sel && sel.rangeCount === 0) {
const r = document.createRange();
r.selectNodeContents(pasteZone);
r.collapse(false);
sel.removeAllRanges();
sel.addRange(r);
}
// wieder verstecken Fokus bleibt (Browser lässt Paste trotzdem zu)
setTimeout(() => pasteZone.classList.add("visually-hidden"), 10);
}
// —— Modal immer CLEAN beim Öffnen ——
clearPreviewAndInputs();
if (mode === "edit") {
titleEl.textContent = "Wunsch bearbeiten";
@@ -123,15 +219,14 @@
const dDesc = btn.getAttribute("data-description") || "";
const dPrice = btn.getAttribute("data-price") || "";
const dLink = btn.getAttribute("data-link") || "";
const dQty = btn.getAttribute("data-qty") || "1"; // <-- NEU
const dQty = btn.getAttribute("data-qty") || "1";
if (fId) fId.value = wishid;
if (fTitle) fTitle.value = dTitle;
if (fDesc) fDesc.value = dDesc;
if (fPrice) fPrice.value = dPrice;
if (fLink) fLink.value = dLink;
if (fImg) fImg.value = "";
if (fQty) fQty.value = dQty; // <-- NEU
if (fQty) fQty.value = dQty;
} else {
titleEl.textContent = "Wunsch hinzufügen";
actionEl.value = "add";
@@ -141,11 +236,170 @@
if (fDesc) fDesc.value = "";
if (fPrice) fPrice.value = "";
if (fLink) fLink.value = "";
if (fImg) fImg.value = "";
if (fQty) fQty.value = "1"; // <-- NEU
if (fQty) fQty.value = "1";
if (removeWrap) removeWrap.style.display = "none";
if (removeChk) removeChk.checked = false;
}
// --- Bild-URL
if (fImgUrl) {
fImgUrl.addEventListener(
"input",
() => {
const val = fImgUrl.value.trim();
if (val !== "") {
clearFile();
clearPaste();
showPreview(val);
} else showPreview("");
},
{ once: true }
);
}
// --- Datei-Upload
if (fImgFile) {
fImgFile.addEventListener(
"change",
() => {
if (fImgFile.files && fImgFile.files[0]) {
const f = fImgFile.files[0];
if (f.size > 8 * 1024 * 1024) {
alert("Datei ist größer als 8 MB.");
fImgFile.value = "";
showPreview("");
return;
}
clearUrl();
clearPaste();
const blobUrl = URL.createObjectURL(f);
showPreview(blobUrl);
} else {
showPreview("");
}
},
{ once: true }
);
}
// --- Paste aus Zwischenablage
if (pasteZone) {
pasteZone.setAttribute(
"data-placeholder",
pasteZone.getAttribute("data-placeholder") ||
"Hier klicken und dann Strg+V / Cmd+V"
);
pasteZone.setAttribute("data-ph-active", "1");
pasteZone.addEventListener(
"focus",
() => {
if (pasteZone.getAttribute("data-ph-active") === "1") {
pasteZone.innerHTML = "";
pasteZone.removeAttribute("data-ph-active");
}
},
{ once: true }
);
pasteZone.addEventListener("blur", () => {
if (pasteZone.innerText.trim() === "") {
pasteZone.innerHTML = "";
pasteZone.setAttribute("data-ph-active", "1");
}
});
// verhindert, dass Text-Schnipsel sichtbar werden
pasteZone.addEventListener("input", () => {
pasteZone.textContent = "";
});
// keine Drops zulassen
["dragover", "drop"].forEach((evName) => {
pasteZone.addEventListener(evName, (e) => {
e.preventDefault();
e.stopPropagation();
});
});
pasteZone.addEventListener(
"paste",
(ev) => {
const items =
ev.clipboardData && ev.clipboardData.items
? ev.clipboardData.items
: [];
let imgItem = null;
for (let i = 0; i < items.length; i++) {
const t = items[i].type || "";
if (t.startsWith("image/")) {
imgItem = items[i];
break;
}
}
// nur Bilder erlaubt
if (!imgItem) {
ev.preventDefault();
// optional Hinweis
alert("Bitte nur Bilder einfügen (z. B. über „Bild kopieren“).");
return;
}
ev.preventDefault();
const blob = imgItem.getAsFile();
if (!blob) return;
if (blob.size > 8 * 1024 * 1024) {
alert("Paste-Bild ist größer als 8 MB.");
return;
}
const ext =
blob.type && blob.type.split("/")[1]
? blob.type.split("/")[1]
: "png";
if (pasteName) pasteName.value = "clipboard." + ext;
const reader = new FileReader();
reader.onload = function () {
const dataUrl = reader.result; // data:image/*;base64,...
if (pasteVal) pasteVal.value = dataUrl;
clearUrl();
clearFile();
showPreview(dataUrl);
};
reader.readAsDataURL(blob);
},
{ once: true }
);
}
if (pasteActivator) {
pasteActivator.addEventListener(
"click",
() => {
// andere Inputs leeren, Preview resetten
clearUrl();
clearFile();
// Fokus in den versteckten Paste-Catcher
focusPasteCatcher();
},
{ once: true }
);
}
// Beim Schließen: wirklich ALLES wieder clean + Blob-URL freigeben
itemModal.addEventListener(
"hidden.bs.modal",
() => {
revokePreviewUrl();
if (prevWrap) prevWrap.style.display = "none";
if (prevImg) prevImg.removeAttribute("src");
clearUrl();
clearFile();
clearPaste();
if (removeChk) removeChk.checked = false;
},
{ once: true }
);
});
}
})();