1// ===== API ===== 2const getItemsPopUp = async () => { 3 const params = ["Id", "Title", "FileRef", "Url", "Publicado"]; 4 const url = `${ 5 location.origin 6 }/_api/web/lists/getbytitle('PopUpHome')/items?$select=${params.join( 7 "," 8 )}&$orderby=Orden asc&$top=5000&$filter=Publicado eq 1`; 9 10 const response = await fetch(url, { 11 headers: { 12 Accept: "application/json;odata=verbose", 13 "Content-Type": "application/json;odata=verbose", 14 }, 15 }); 16 const data = await response.json(); 17 return data.d.results; 18}; 19 20// ===== Helpers de UI ===== 21const injectPopupStyles = () => { 22 if (document.getElementById("popup-anim-styles")) return; 23 const style = document.createElement("style"); 24 style.id = "popup-anim-styles"; 25 style.textContent = ` 26 /* Contenedor: fade */ 27 #PopUp { opacity: 1; transition: opacity .28s ease; } 28 #PopUp.closing { opacity: 0; } 29 30 /* Contenido: ligero zoom-out al cerrar */ 31 #PopUp .pop-content { transform: scale(1); transition: transform .28s ease; } 32 #PopUp.closing .pop-content { transform: scale(.97); } 33 34 /* Ãrea clicable del botón */ 35 #PopUp .btn-close { cursor: pointer; } 36 #PopUp .btn-close:active { transform: scale(.96); } 37 `; 38 document.head.appendChild(style); 39}; 40 41const closePopup = () => { 42 const popup = document.getElementById("PopUp"); 43 if (!popup) return; 44 // activa animación 45 popup.classList.add("closing"); 46 // elimina luego de la animación 47 setTimeout(() => popup.remove(), 300); 48}; 49 50// ===== Render ===== 51document.addEventListener("DOMContentLoaded", async () => { 52 injectPopupStyles(); 53 54 const section = document.createElement("section"); 55 section.className = 56 "bg-black fixed inset-0 p-[20px] z-[9999] bg-opacity-50 backdrop-blur-sm flex items-center justify-center hidden"; 57 section.id = "PopUp"; 58 section.innerHTML = ` 59 <ul class="pop-content rounded-lg overflow-hidden sm:w-[600px] w-full relative" id="pop-up-content"></ul> 60 `; 61 document.body.insertBefore(section, document.body.firstChild); 62 63 const PopUp = document.getElementById("PopUp"); 64 const popUpContent = document.getElementById("pop-up-content"); 65 66 const items = await getItemsPopUp(); 67 68 if (items.length !== 0) { 69 PopUp.classList.remove("hidden"); 70 } else { 71 return; // no hay nada que mostrar 72 } 73 74 if (items.length === 1) { 75 const item = addItem(items[0]); 76 popUpContent.appendChild(item); 77 } 78 79 if (items.length > 1) { 80 const splide = document.createElement("div"); 81 splide.className = "splide"; 82 83 const splideTrack = document.createElement("div"); 84 splideTrack.className = "splide__track"; 85 const splideList = document.createElement("ul"); 86 splideList.className = "splide__list"; 87 88 items.forEach((item) => { 89 const li = document.createElement("li"); 90 li.className = "splide__slide"; 91 const a = addItem(item); 92 li.appendChild(a); 93 splideList.appendChild(li); 94 }); 95 96 splideTrack.appendChild(splideList); 97 splide.appendChild(splideTrack); 98 popUpContent.appendChild(splide); 99 100 // Asegúrate de tener Splide cargado en la página 101 new Splide(splide, { 102 type: "loop", 103 perPage: 1, 104 perMove: 1, 105 pagination: false, 106 arrows: true, 107 autoplay: true, 108 interval: 5000, 109 speed: 1000, 110 }).mount(); 111 } 112 113 // Botón de cerrar (ahora toda el área es clicable) 114 popUpContent.appendChild(closeItem()); 115 116 // (Opcional) Cerrar con ESC 117 document.addEventListener("keydown", (e) => { 118 if (e.key === "Escape") closePopup(); 119 }); 120}); 121 122const closeItem = () => { 123 // Un solo botón grande y clicable (no anidar <button> dentro) 124 const btn = document.createElement("button"); 125 btn.type = "button"; 126 btn.className = 127 "btn-close flex items-center justify-center bg-[#f2f2f2] text-black " + 128 "rounded-full w-[36px] h-[36px] absolute right-2 top-2 shadow " + 129 "border border-gray-300 cursor-pointer border-solid !m-0 z-[99]"; 130 btn.setAttribute("aria-label", "Cerrar PopUp"); 131 132 // Ãcono 133 btn.innerHTML = `<i class="fa-solid fa-x text-[14px] leading-none"></i>`; 134 135 // Cierra al hacer clic en cualquier parte del botón 136 btn.addEventListener("click", closePopup); 137 138 return btn; 139}; 140 141const addItem = (item) => { 142 const a = document.createElement("a"); 143 a.className = "block"; // para tener área clicable completa del contenido 144 145 if (item.Url) { 146 a.href = item.Url; 147 a.target = "_blank"; 148 } 149 150 if (item.FileRef?.toLowerCase().endsWith(".mp4")) { 151 a.appendChild(videoHTML(item)); 152 } else { 153 a.appendChild(imageHTML(item)); 154 } 155 return a; 156};
157 158const videoHTML = (item) => { 159 const video = document.createElement("video"); 160 video.src = item.FileRef; 161 video.controls = true; 162 video.classList.add("object-contain", "h-full", "w-full", "max-h-[70vh]"); 163 return video; 164}; 165 166const imageHTML = (item) => { 167 const wrapper = document.createElement("div"); 168 wrapper.className = ` 169 relative w-full h-[80vh] max-h-[70vh] flex items-center justify-center 170 overflow-hidden rounded-lg bg-black 171 `; 172 173 // Fondo borroso 174 const backgroundImg = document.createElement("img"); 175 backgroundImg.src = item.FileRef; 176 backgroundImg.alt = item.Title ?? ""; 177 backgroundImg.className = ` 178 absolute inset-0 w-full h-full object-cover 179 filter blur-xl 180 `; 181 182 // Imagen principal 183 const img = document.createElement("img"); 184 img.src = item.FileRef; 185 img.alt = item.Title ?? ""; 186 img.classList.add("object-contain", "h-[70vh]", "w-full", "z-10"); 187 188 wrapper.appendChild(backgroundImg); 189 wrapper.appendChild(img); 190 191 return wrapper; 192};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.