406 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			406 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // js/wishlist.js
 | ||
| (function () {
 | ||
|   "use strict";
 | ||
| 
 | ||
|   // ===== 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 = $("#reservationModal");
 | ||
|   if (reservationModal) {
 | ||
|     reservationModal.addEventListener("show.bs.modal", function (ev) {
 | ||
|       const btn = ev.relatedTarget;
 | ||
|       if (!btn) return;
 | ||
|       const wishid = btn.getAttribute("data-wishid");
 | ||
|       const reserved = btn.getAttribute("data-reserved");
 | ||
| 
 | ||
|       $("#modal-wishid", reservationModal).value = wishid || "";
 | ||
|       $("#modal-reservedstat", reservationModal).value = reserved || "";
 | ||
| 
 | ||
|       const submitBtn = $("#reservation-submit", reservationModal);
 | ||
|       const titleEl = $("#reservationModalLabel", reservationModal);
 | ||
|       const infoEl = $("#ReservationInfoText", reservationModal);
 | ||
| 
 | ||
|       if (reserved === "1") {
 | ||
|         submitBtn.textContent = "Reservierung aufheben";
 | ||
|         titleEl.textContent = "Reservierung aufheben";
 | ||
|         if (infoEl) infoEl.style.display = "none";
 | ||
|       } else {
 | ||
|         submitBtn.textContent = "Reservieren";
 | ||
|         titleEl.textContent = "Wunsch reservieren";
 | ||
|         if (infoEl) infoEl.style.display = "";
 | ||
|       }
 | ||
|     });
 | ||
|   }
 | ||
| 
 | ||
|   // ===== Delete Modal =====
 | ||
|   const deleteModal = $("#deleteModal");
 | ||
|   if (deleteModal) {
 | ||
|     deleteModal.addEventListener("show.bs.modal", function (ev) {
 | ||
|       const btn = ev.relatedTarget;
 | ||
|       if (!btn) return;
 | ||
|       const card = btn.closest(".card");
 | ||
|       const title = card
 | ||
|         ? card.querySelector(".card-title")?.textContent?.trim() || ""
 | ||
|         : "";
 | ||
|       const wishid = btn.getAttribute("data-wishid") || "";
 | ||
| 
 | ||
|       const idInput = deleteModal.querySelector(
 | ||
|         '#DelWhishID, #WhishID, input[name="WhishID"]'
 | ||
|       );
 | ||
|       const titleEl = deleteModal.querySelector(
 | ||
|         "#del-whish-title, #whish-title"
 | ||
|       );
 | ||
| 
 | ||
|       if (idInput) idInput.value = wishid;
 | ||
|       if (titleEl) titleEl.textContent = title || "Wunsch";
 | ||
|     });
 | ||
|   }
 | ||
| 
 | ||
|   // ===== Push Prio Modal =====
 | ||
|   const prioModal = $("#pushprioModal");
 | ||
|   if (prioModal) {
 | ||
|     prioModal.addEventListener("show.bs.modal", function (ev) {
 | ||
|       const btn = ev.relatedTarget;
 | ||
|       if (!btn) return;
 | ||
|       const card = btn.closest(".card");
 | ||
|       const title = card
 | ||
|         ? card.querySelector(".card-title")?.textContent?.trim() || ""
 | ||
|         : "";
 | ||
|       const wishid = btn.getAttribute("data-wishid") || "";
 | ||
| 
 | ||
|       const idInput = prioModal.querySelector(
 | ||
|         '#PrioWhishID, #WhishID, input[name="WhishID"]'
 | ||
|       );
 | ||
|       const titleEl = prioModal.querySelector(
 | ||
|         "#prio-whish-title, #whish-title"
 | ||
|       );
 | ||
| 
 | ||
|       if (idInput) idInput.value = wishid;
 | ||
|       if (titleEl) titleEl.textContent = title || "Wunsch";
 | ||
|     });
 | ||
|   }
 | ||
| 
 | ||
|   // ===== 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 = $("#itemModalTitle", itemModal);
 | ||
|       const actionEl = $("#ItemAction", itemModal);
 | ||
|       const submitEl = $("#ItemSubmitBtn", itemModal);
 | ||
|       const removeWrap = $("#RemoveImageWrap", itemModal);
 | ||
|       const removeChk = $("#RemoveImage", itemModal);
 | ||
| 
 | ||
|       // Felder
 | ||
|       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";
 | ||
|         actionEl.value = "edit";
 | ||
|         submitEl.textContent = "Speichern";
 | ||
|         if (removeWrap) removeWrap.style.display = "";
 | ||
|         if (removeChk) removeChk.checked = false;
 | ||
| 
 | ||
|         const wishid = btn.getAttribute("data-wishid") || "-1";
 | ||
|         const dTitle = btn.getAttribute("data-title") || "";
 | ||
|         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";
 | ||
| 
 | ||
|         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 (fQty) fQty.value = dQty;
 | ||
|       } else {
 | ||
|         titleEl.textContent = "Wunsch hinzufügen";
 | ||
|         actionEl.value = "add";
 | ||
|         submitEl.textContent = "Hinzufügen";
 | ||
|         if (fId) fId.value = "-1";
 | ||
|         if (fTitle) fTitle.value = "";
 | ||
|         if (fDesc) fDesc.value = "";
 | ||
|         if (fPrice) fPrice.value = "";
 | ||
|         if (fLink) fLink.value = "";
 | ||
|         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 }
 | ||
|       );
 | ||
|     });
 | ||
|   }
 | ||
| })();
 |