1/** 2 * hk-kerkese modal â isolated opener for https://web.hostinkos.com/ 3 * Desktop: modal + iframe on web.hostinkos.com (PHP + Turnstile live there); 4 * if iframe fails ready ping â new tab 5 * Mobile: full-page navigate 6 * 7 * Note: do NOT embed apex /web/ â origin PHP under /web/*.php is broken 8 * ("No input file specified") and Turnstile is bound to web.hostinkos.com. 9 */ 10(function () { 11 var BASE = "https://web.hostinkos.com/"; 12 var FORM_ORIGINS = { 13 "https://web.hostinkos.com": 1 14 }; 15 var ALLOWED_PARENTS = { 16 "https://hostinkos.com": 1, 17 "https://www.hostinkos.com": 1 18 }; 19 var READY_MS = 8000; 20 /** Bump when form HTML/JS changes â forces iframe past CF/browser cache */ 21 var EMBED_CACHE_BUST = "20260916nisje"; 22 var PAKO_ALIAS = { 23 "web-mini": "web-nisje", 24 "web-pro": "web-biznes", 25 "web-pro-plus": "web-biznes-plus", 26 "web-shop": "web-dyqan", 27 "web-shop-max": "web-dyqan-pro", 28 "web-shop-custom": "web-dyqan-plus" 29 }; 30 31 function normalizeFormParams(u) { 32 var pako = u.searchParams.get("pako"); 33 if (pako && PAKO_ALIAS[pako]) u.searchParams.set("pako", PAKO_ALIAS[pako]); 34 var need = u.searchParams.get("need"); 35 if (need && PAKO_ALIAS[need]) { 36 u.searchParams.set("need", "webfaqe_re"); 37 if (!u.searchParams.get("pako")) u.searchParams.set("pako", PAKO_ALIAS[need]); 38 } else if (need === "mini" || need === "landing" || need === "web-mini") { 39 u.searchParams.set("need", "webfaqe_re"); 40 if (!u.searchParams.get("pako")) u.searchParams.set("pako", "web-nisje"); 41 } 42 } 43 44 var isEn = 45 (document.documentElement.lang || "").toLowerCase().indexOf("en") === 0 || 46 (window.location.pathname || "").indexOf("/en/") === 0; 47 48 var T = isEn 49 ? { 50 close: "Close", 51 title: "Website request", 52 thanks: "Thank you â your request was sent", 53 msgEmail: "We will reply by email.", 54 msgPhone: "We will contact you by phone or WhatsApp during office hours.", 55 openTab: "Open the form in a new tab", 56 frameTitle: "Website request form" 57 } 58 : { 59 close: "Mbyll", 60 title: "Kërkesë për webfaqe", 61 thanks: "Faleminderit â kërkesa u dërgua", 62 msgEmail: "Ju kthejmë përgjigje me email.", 63 msgPhone: "Do t'ju kontaktojmë me telefon ose WhatsApp në orarin e zyrës.", 64 openTab: "Hap formularin në tab të ri", 65 frameTitle: "Formular kërkese webfaqe" 66 }; 67 68 var modal = null; 69 var frame = null; 70 var openTab = null; 71 var successEl = null; 72 var successMsgEl = null; 73 var fallbackEl = null; 74 var lastFocus = null; 75 var readyTimer = null; 76 var awaitingReady = false; 77 var pendingTabUrl = ""; 78 79 function isMobile() { 80 return window.matchMedia("(max-width: 767px)").matches; 81 } 82 83 function buildUrl(el, forModal) { 84 var u = new URL(BASE); 85 var pako = el.getAttribute("data-pako"); 86 var need = el.getAttribute("data-need"); 87 if (pako) u.searchParams.set("pako", pako); 88 if (need) u.searchParams.set("need", need); 89 var href = el.getAttribute("href"); 90 if ((!pako && !need) && href && href.indexOf("web.hostinkos.com") !== -1) { 91 try { 92 var fromHref = new URL(href, window.location.href); 93 fromHref.searchParams.forEach(function (val, key) { 94 if (key === "embed") return; 95 if (!u.searchParams.has(key)) u.searchParams.set(key, val); 96 }); 97 } catch (eHref) {} 98 } 99 if (forModal) { 100 u.searchParams.set("embed", "1"); 101 u.searchParams.set("_v", EMBED_CACHE_BUST); 102 u.searchParams.set("_t", String(Date.now())); 103 } 104 normalizeFormParams(u); 105 return u.toString(); 106 } 107 108 function clearReadyWatch() { 109 awaitingReady = false; 110 if (readyTimer) { 111 clearTimeout(readyTimer); 112 readyTimer = null; 113 } 114 } 115 116 function openInNewTab(url) { 117 clearReadyWatch(); 118 var u = url || pendingTabUrl || BASE; 119 try { 120 var w = window.open(u, "_blank", "noopener,noreferrer"); 121 if (!w) { 122 // Popup blocked â same-tab navigate 123 window.location.href = u; 124 return; 125 } 126 } catch (eOpen) { 127 window.location.href = u; 128 return; 129 } 130 closeKerkeseQuiet(); 131 } 132 133 function cacheNodes() { 134 frame = modal.querySelector("#hkKerkeseFrame") || modal.querySelector("iframe"); 135 openTab = modal.querySelector("#hkKerkeseOpenTab"); 136 successEl = modal.querySelector("#hkKerkeseSuccess"); 137 successMsgEl = modal.querySelector("#hkKerkeseSuccessMsg"); 138 fallbackEl = modal.querySelector(".hk-kerkese-modal__fallback"); 139 } 140 141 function ensureModal() { 142 var existing = document.getElementById("hkKerkeseModal"); 143 if (existing && !existing.querySelector("iframe.hk-kerkese-modal__frame")) { 144 existing.remove(); 145 existing = null; 146 modal = null; 147 } 148 if (modal && document.body.contains(modal) && modal.querySelector("iframe")) { 149 cacheNodes(); 150 return modal; 151 } 152 if (existing) existing.remove(); 153 modal = document.createElement("div"); 154 modal.id = "hkKerkeseModal"; 155 modal.className = "hk-kerkese-modal"; 156 modal.setAttribute("hidden", ""); 157 modal.innerHTML = 158 '<button type="button" class="hk-kerkese-modal__backdrop" data-hk-close aria-label="' + 159 T.close + 160 '"></button>' + 161 '<div class="hk-kerkese-modal__dialog" role="dialog" aria-modal="true" aria-label="' + 162 T.title + 163 '">' + 164 '<button type="button" class="hk-kerkese-modal__close" data-hk-close aria-label="' + 165 T.close + 166 '">
166Ã</button>' + 167 '<iframe class="hk-kerkese-modal__frame" id="hkKerkeseFrame" title="' + 168 T.frameTitle + 169 '" src="about:blank"></iframe>' + 170 '<div class="hk-kerkese-modal__success" id="hkKerkeseSuccess" hidden tabindex="-1" role="status" aria-live="polite">' + 171 "<h2>" + 172 T.thanks + 173 "</h2>" + 174 '<p class="hk-kerkese-modal__success-msg" id="hkKerkeseSuccessMsg"></p>' + 175 '<button type="button" class="hk-kerkese-modal__success-btn" data-hk-close>' + 176 T.close + 177 "</button>" + 178 "</div>" + 179 '<p class="hk-kerkese-modal__fallback">' + 180 '<a id="hkKerkeseOpenTab" href="' + 181 BASE + 182 '" target="_blank" rel="noopener noreferrer">' + 183 T.openTab + 184 "</a>" + 185 "</p></div>"; 186 document.body.appendChild(modal); 187 cacheNodes(); 188 modal.querySelectorAll("[data-hk-close]").forEach(function (el) { 189 el.addEventListener("click", closeKerkese); 190 }); 191 if (frame) { 192 frame.addEventListener("error", function () { 193 if (awaitingReady) openInNewTab(pendingTabUrl); 194 }); 195 } 196 return modal; 197 } 198 199 function showFormView() { 200 if (frame) { 201 frame.hidden = false; 202 frame.removeAttribute("hidden"); 203 frame.removeAttribute("aria-hidden"); 204 } 205 if (successEl) { 206 successEl.hidden = true; 207 successEl.setAttribute("hidden", ""); 208 } 209 if (fallbackEl) { 210 fallbackEl.hidden = false; 211 fallbackEl.removeAttribute("hidden"); 212 } 213 if (modal) modal.classList.remove("hk-kerkese-modal--success"); 214 } 215 216 function showSuccessView(channel) { 217 clearReadyWatch(); 218 ensureModal(); 219 var msg = channel === "phone_or_wa" ? T.msgPhone : T.msgEmail; 220 if (successMsgEl) successMsgEl.textContent = msg; 221 if (frame) { 222 frame.hidden = true; 223 frame.setAttribute("hidden", ""); 224 frame.setAttribute("aria-hidden", "true"); 225 frame.src = "about:blank"; 226 } 227 if (fallbackEl) { 228 fallbackEl.hidden = true; 229 fallbackEl.setAttribute("hidden", ""); 230 } 231 if (successEl) { 232 successEl.hidden = false; 233 successEl.removeAttribute("hidden");
234 try { 235 successEl.focus(); 236 } catch (eFocus) {} 237 } 238 if (modal) modal.classList.add("hk-kerkese-modal--success"); 239 } 240 241 function startReadyWatch(tabUrl) { 242 clearReadyWatch(); 243 awaitingReady = true; 244 pendingTabUrl = tabUrl; 245 readyTimer = setTimeout(function () { 246 if (awaitingReady) openInNewTab(tabUrl); 247 }, READY_MS); 248 } 249 250 function openKerkese(el) { 251 var tabUrl = buildUrl(el, false); 252 if (isMobile()) { 253 window.location.href = tabUrl; 254 return; 255 } 256 try { 257 var embedUrl = buildUrl(el, true); 258 ensureModal(); 259 showFormView(); 260 lastFocus = document.activeElement; 261 if (openTab) openTab.href = tabUrl; 262 if (!frame) { 263 openInNewTab(tabUrl); 264 return; 265 } 266 startReadyWatch(tabUrl); 267 // Force a real reload (same-origin iframe can keep a stale cached document) 268 try { 269 frame.src = "about:blank"; 270 } catch (eBlank) {} 271 frame.src = embedUrl; 272 modal.hidden = false; 273 modal.removeAttribute("hidden"); 274 document.body.classList.add("hk-kerkese-modal-open"); 275 // Modal itself didn't become visible â new tab 276 if (modal.hidden || modal.getAttribute("hidden") !== null) { 277 openInNewTab(tabUrl); 278 return; 279 } 280 var closeBtn = modal.querySelector(".hk-kerkese-modal__close"); 281 if (closeBtn) { 282 try { 283 closeBtn.focus(); 284 } catch (eFocus) {} 285 } 286 } catch (eOpen) { 287 openInNewTab(tabUrl); 288 } 289 } 290 291 function closeKerkeseQuiet() { 292 clearReadyWatch(); 293 if (!modal) return; 294 modal.hidden = true; 295 modal.setAttribute("hidden", ""); 296 document.body.classList.remove("hk-kerkese-modal-open"); 297 if (frame) frame.src = "about:blank"; 298 } 299 300 function closeKerkese() { 301 clearReadyWatch(); 302 if (!modal || modal.hidden) return; 303 modal.hidden = true; 304 modal.setAttribute("hidden", ""); 305 document.body.classList.remove("hk-kerkese-modal-open"); 306 showFormView(); 307 if (frame) frame.src = "about:blank"; 308 if (lastFocus && typeof lastFocus.focus === "function") { 309 try { 310 lastFocus.focus(); 311 } catch (eBack) {} 312 } 313 } 314 315 document.addEventListener("click", function (e) { 316 var el = e.target.closest(".js-hk-kerkese"); 317 if (!el) return; 318 e.preventDefault(); 319 openKerkese(el); 320 }); 321 document.addEventListener("keydown", function (e) { 322 if (e.key === "Escape") closeKerkese(); 323 }); 324 window.addEventListener("message", function (e) { 325 if (!FORM_ORIGINS[e.origin]) return; 326 if (!e.data || !e.data.type) return; 327 if (!ALLOWED_PARENTS[window.location.origin]) return; 328 if (e.data.type === "hk-kerkese-ready") { 329 clearReadyWatch(); 330 return; 331 } 332 if (e.data.type === "hk-kerkese-success") { 333 showSuccessView(e.data.reply_channel || "email"); 334 } 335 }); 336})();
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.