PageSourceSearch

https://bitontolive.it/wp-content/themes/livenetwork-theme/assets/js/live.js?ver=1787240211

js bitontolive.it collected 2026-09-25 05:50:49 UTC 19,196 bytes, 577 lines download raw bytes

1// ============================================================
2// LIVE.JS - Script principale tema LiveNetwork
3// Gestisce menu, overlay, ricerca, password, validazioni e fade menu scroll
4// ============================================================
5
6document.addEventListener("DOMContentLoaded", function () {
7  try {
8    // ------------------------------------------------------------
9    // MENU SINISTRO / DESTRO + OVERLAY
10    // ------------------------------------------------------------
11    var toggle = document.getElementById("btnSidebarLeft");
12    var sideMenu = document.getElementById("side-menu");
13    var overlay = document.getElementById("menu-overlay");
14    var closeBtns = document.querySelectorAll(".menu-close");
15    var btnRight = document.getElementById("btnSidebarRight");
16    var sideRight = document.getElementById("side-menu-right");
17
18    if (toggle && sideMenu && overlay) {
19      toggle.addEventListener("click", function () {
20        sideMenu.classList.add("active");
21        overlay.classList.add("active");
22      });
23
24      overlay.addEventListener("click", function () {
25        sideMenu.classList.remove("active");
26        if (sideRight) sideRight.classList.remove("active");
27        overlay.classList.remove("active");
28      });
29    }
30
31    if (btnRight && sideRight && overlay) {
32      btnRight.addEventListener("click", function () {
33        sideRight.classList.add("active");
34        overlay.classList.add("active");
35      });
36    }
37
38    if (closeBtns && closeBtns.length) {
39      closeBtns.forEach(function (btn) {
40        btn.addEventListener("click", function () {
41          if (sideMenu) sideMenu.classList.remove("active");
42          if (sideRight) sideRight.classList.remove("active");
43          if (overlay) overlay.classList.remove("active");
44        });
45      });
46    }
47
48    // ------------------------------------------------------------
49    // RICERCA PRINCIPALE
50    // ------------------------------------------------------------
51    var btnSearch = document.getElementById("btnSearch");
52    var btnSearchInner = document.getElementById("btnSearchInner");
53    var searchBox = document.querySelector(".live-main-search-box");
54    var inputSearch =
55      searchBox && searchBox.querySelector(".livenetwork-live-search__input")
56        ? searchBox.querySelector(".livenetwork-live-search__input")
57        : null;
58
59    function toggleSearchBox() {
60      if (!searchBox) return;
61
62      searchBox.classList.toggle("active");
63
64      if (searchBox.classList.contains("overflow-visible")) {
65        searchBox.classList.remove("overflow-visible");
66        if (inputSearch) inputSearch.value = "";
67      } else {
68        if (inputSearch) inputSearch.focus();
69      }
70    }
71
72    if (btnSearch && searchBox) {
73      btnSearch.addEventListener("click", toggleSearchBox);
74    }
75
76    if (btnSearchInner && searchBox) {
77      btnSearchInner.addEventListener("click", toggleSearchBox);
78
79      // Classe quando l'animazione finisce (serve per overflow visibile)
80      searchBox.addEventListener("transitionend", function () {
81        if (searchBox.classList.contains("active")) {
82          searchBox.classList.add("overflow-visible");
83        }
84      });
85    }
86
87    // ------------------------------------------------------------
88    // TOGGLE PASSWORD 👁️ / 🙈
89    // ------------------------------------------------------------
90    function bindPasswordToggles(root) {
91      root = root || document;
92      var buttons = root.querySelectorAll(
93        ".live-password-field .toggle-password"
94      );
95      if (!buttons || !buttons.length) return;
96
97      buttons.forEach(function (btn) {
98        if (btn.dataset.bound === "1") return;
99        btn.dataset.bound = "1";
100
101        btn.addEventListener("click", function (e) {
102          e.preventDefault();
103
104          var wrapper = btn.closest(".live-password-field");
105          if (!wrapper) return;
106
107          var input = wrapper.querySelector(
108            'input[type="password"], input[type="text"]'
109          );
110          if (!input) return;
111
112          var isHidden = input.type === "password";
113          input.type = isHidden ? "text" : "password";
114          btn.classList.toggle("active", isHidden);
115          btn.setAttribute("aria-pressed", isHidden ? "true" : "false");
116        });
117      });
118    }
119
120bindPasswordToggles(document);
121
122    // ------------------------------------------------------------
123    // VALIDAZIONE LOGIN (HTML5)
124    // ------------------------------------------------------------
125    function bindLoginValidation(root) {
126      root = root || document;
127      var form = root.querySelector(".live-login-form");
128      if (!form) return;
129
130      form.addEventListener("submit", function (e) {
131        if (!form.checkValidity()) {
132          e.preventDefault();
133          form.reportValidity();
134          return;
135        }
136      });
137    }
138
139    bindLoginValidation(document);
140
141    // ------------------------------------------------------------
142    // VALIDAZIONE PASSWORD (feedback UI)
143    // ------------------------------------------------------------
144    function bindPasswordStrength(root) {
145      root = root || document;
146
147      var passInput = root.querySelector(
148        'form.live-register-form input[name="user_pass"]'
149      );
150      var hint = root.querySelector("form.live-register-form #password-strength");
151      if (!passInput || !hint) return;
152
153      function meetsPolicy(v) {
154        return (
155          v.length >= 8 &&
156          /[A-Z]/.test(v) &&
157          /\d/.test(v) &&
158          /[^A-Za-z0-9]/.test(v)
159        );
160      }
161
162      function isStrong(v) {
163        return (
164          v.length >= 12 &&
165          /[a-z]/.test(v) &&
166          /[A-Z]/.test(v) &&
167          /\d/.test(v) &&
168          /[^A-Za-z0-9]/.test(v)
169        );
170      }
171
172      function render() {
173        var val = (passInput.value || "").trim();
174
175        if (!val.length) {
176          hint.textContent =
177            "La tua password deve contenere almeno 8 caratteri, una lettera maiuscola, un numero e un simbolo.";
178          hint.className = "password-hint";
179          return;
180        }
181
182        if (!meetsPolicy(val)) {
183          hint.textContent = "Password troppo debole";
184          hint.className = "password-hint weak";
185          return;
186        }
187
188        if (isStrong(val)) {
189          hint.textContent = "Password forte";
190          hint.className = "password-hint strong";
191        } else {
192          hint.textContent = "Password accettabile";
193          hint.className = "password-hint medium";
194        }
195      }
196
197      passInput.addEventListener("input", render);
198      render();
199    }
200
201    // ------------------------------------------------------------
202    // VALIDAZIONE REGISTRAZIONE (HTML5 + policy password)
203    // ------------------------------------------------------------
204    function bindRegisterValidation(root) {
205      root = root || document;
206
207      var form = root.querySelector("form.live-register-form");
208      if (!form) return;
209
210      var passInput = form.querySelector('input[name="user_pass"]');
211      var hint = form.querySelector("#password-strength");
212
213      function meetsPolicy(v) {
214        return (
215          v.length >= 8 &&
216          /[A-Z]/.test(v) &&
217          /\d/.test(v) &&
218          /[^A-Za-z0-9]/.test(v)
219        );
220      }
221
222      form.addEventListener("submit", function (e) {
223        if (!form.checkValidity()) {
224          e.preventDefault();
225          form.reportValidity();
226          return;
227        }
228
229        var val = ((passInput && passInput.value) || "").trim();
230        if (!meetsPolicy(val)) {
231          e.preventDefault();
232          if (hint) {
233            hint.textContent =
234              "La password non rispetta i requisiti di sicurezza.";
235            hint.className = "password-hint weak";
236          }
237          if (passInput) passInput.focus();
238        }
239      });
240    }
241
242    bindPasswordStrength(document);
243    bindRegisterValidation(document);
244
245    // ------------------------------------------------------------
246    // UPLOAD FOTO PROFILO DURANTE LA REGISTRAZIONE
247    // (FIX: niente return “globale” se mancano progress/bar)
248    // ------------------------------------------------------------
249    (function initRegisterAvatarUpload() {
250      var avatarWrapper = document.querySelector(".avatar-wrapper");
251      var inputFile = document.getElementById("user_profile_upload");
252      if (!avatarWrapper || !inputFile) return;
253
254      var avatarPreview = document.getElementById("avatar-preview");
255      var progressBar = document.querySelector(".upload-progress");
256      var bar = progressBar ? progressBar.querySelector(".bar") : null;
257      var removeBtn = document.getElementById("remove-avatar");
258      var hiddenField = document.getElementById("user_profile_image");
259      var registerBtn = document.querySelector(
260        'button[name="live_register_submit"]'
261      );
262
263      if (!progressBar || !bar) {
264        console.warn(
265          "[live.js] upload progress missing: skip avatar upload init"
266        );
267        return; // <-- esce SOLO da questa IIFE, non blocca il resto del file
268      }
269
270      avatarWrapper.addEventListener("click", function () {
271        inputFile.click();
272      });
273
274      inputFile.addEventListener("change", function () {
275        var file = inputFile.files && inputFile.files[0];
276        if (!file) return;
277
278        var allowed = ["image/jpeg", "image/png", "image/webp"];
279        if (allowed.indexOf(file.type) === -1) {
280          alert("Formato non supportato. Usa JPG, PNG o WEBP.");
281          return;
282        }
283
284        if (file.size > 3 * 1024 * 1024) {
285          alert("L’immagine non deve superare i 3 MB.");
286          return;
287        }
288
289        if (registerBtn) registerBtn.disabled = true;
290        progressBar.style.display = "block";
291        progressBar.classList.remove("indeterminate");
292        bar.style.width = "0%";
293
294        var formData = new FormData();
295        formData.append("action", "live_upload_avatar");
296        formData.append("avatar", file);
297
298        var xhr = new XMLHttpRequest();
299        xhr.open("POST", LiveNetworkData.ajaxurl, true);
300
301        // PROGRESS: massima al 90% durante l'upload
302        xhr.upload.addEventListener("progress", function (e) {
303          if (e.lengthComputable) {
304            var percent = (e.loaded / e.total) * 100;
305            var shown = Math.min(90, Math.max(5, percent));
306            bar.style.width = shown + "%";
307          } else {
308            progressBar.classList.add("indeterminate");
309          }
310        });
311
312        // Upload finito ma il server sta ancora elaborando
313        xhr.upload.addEventListener("load", function () {
314          progressBar.classList.remove("indeterminate");
315          bar.style.width = "95%";
316        });
317
318        // Risposta ricevuta dal server → chiudi a 100% e nascondi
319        xhr.addEventListener("load", function () {
320          var ok = xhr.status === 200;
321          bar.style.width = "100%";
322
323          setTimeout(function () {
324            if (ok) {
325              var res;
326              try {
327                res = JSON.parse(xhr.responseText);
328              } catch (err) {
329                console.error("Errore di parsing JSON:", err);
330                alert("Risposta non valida dal server.");
331                progressBar.style.display = "none";
332                bar.style.width = "0%";
333                if (registerBtn) registerBtn.disabled = false;
334                return;
335              }
336
337              if (res && res.success) {
338                if (avatarPreview) avatarPreview.src = res.data.url;
339                if (hiddenField) hiddenField.value = res.data.id;
340                if (removeBtn) removeBtn.classList.add("show");
341              } else {
342                alert((res && res.data) || "Errore durante l’upload");
343              }
344            } else {
345              alert("Errore di rete durante il caricamento");
346            }
347
348            progressBar.style.display = "none";
349            bar.style.width = "0%";
350            if (registerBtn) registerBtn.disabled = false;
351          }, 250);
352        });
353
354        xhr.addEventListener("error", function () {
355          progressBar.classList.remove("indeterminate");
356          alert("Errore di rete durante il caricamento");
357          progressBar.style.display = "none";
358          bar.style.width = "0%";
359          if (registerBtn) registerBtn.disabled = false;
360        });
361
362        xhr.send(formData);
363      });
364
365      if (removeBtn) {
366        removeBtn.addEventListener("click", function (e) {
367          e.preventDefault();
368          e.stopPropagation();
369
370          if (avatarPreview && avatarPreview.dataset.default) {
371            avatarPreview.src = avatarPreview.dataset.default;
372          }
373          if (hiddenField) hiddenField.value = "";
374          removeBtn.classList.remove("show");
375        });
376      }
377    })();
378
379    // ------------------------------------------------------------
380    // A11Y (PageSpeed/Lighthouse): Complianz labels
381    // ------------------------------------------------------------
382    var complianzLinks = document.querySelectorAll(
383      ".cmplz-documents a.cmplz-link"
384    );
385    if (complianzLinks && complianzLinks.length) {
386      complianzLinks.forEach(function (a) {
387        var hasLabel = !!a.getAttribute("aria-label");
388        var txt = (a.textContent || "").trim();
389
390        var label = "";
391        if (a.classList.contains("cookie-statement")) label = "Apri la Cookie Policy";
392        else if (a.classList.contains("privacy-statement")) label = "Apri la Privacy Policy";
393        else label = txt ? "Apri documento: " + txt : "Apri documento informativo";
394
395        if (!hasLabel) a.setAttribute("aria-label", label);
396
397        if (!txt) {
398          a.insertAdjacentHTML(
399            "beforeend",
400            '<span class="screen-reader-text">' + label + "</span>"
401          );
402        }
403      });
404    }
405
406	// ------------------------------------------------------------
407	// DRAG TO SCROLL (desktop)
408	// - trascina con mouse/pointer per scroll orizzontale
409	// - soglia per non “rompere” i click sui link
410	// ------------------------------------------------------------
411	
412function enableHeaderMenuDrag(nav, scheduleUpdate) {
413  if (!nav) return;
414
415  // ✅ drag solo su desktop (pointer fine + hover) -> niente interferenze su mobile
416  var canDragDesktop = window.matchMedia
417    ? window.matchMedia("(pointer: fine) and (hover: hover)").matches
418    : true;
419
420  if (!canDragDesktop) return;
421
422  nav.addEventListener("dragstart", function (e) { e.preventDefault(); });
423  nav.querySelectorAll("a, img").forEach(function (el) { el.draggable = false; });
424
425  var isDown = false, startX = 0, startScrollLeft = 0;
426  var moved = false, dragging = false, capturedId = null;
427  var TH = 6;
428
429  nav.addEventListener("pointerdown", function (e) {
430    // ✅ solo mouse
431    if (e.pointerType !== "mouse") return;
432    if (e.button !== 0) return;
433
434    isDown = true;
435    moved = false;
436    dragging = false;
437    capturedId = null;
438    startX = e.clientX;
439    startScrollLeft = nav.scrollLeft;
440  });
441
442  nav.addEventListener("pointermove", function (e) {
443    if (!isDown) return;
444    if (e.pointerType !== "mouse") return;
445
446    var dx = e.clientX - startX;
447
448    if (!dragging && Math.abs(dx) > TH) {
449      dragging = true;
450      moved = true;
451      nav.classList.add("is-dragging");
452      if (nav.setPointerCapture && typeof e.pointerId === "number") {
453        try { nav.setPointerCapture(e.pointerId); capturedId = e.pointerId; } catch (_) {}
454      }
455    }
456
457    if (!dragging) return;
458
459    nav.scrollLeft = startScrollLeft - dx;
460    if (typeof scheduleUpdate === "function") scheduleUpdate();
461
462    // ✅ ok qui perché è mouse (non touch)
463    e.preventDefault();
464  }, { passive: false });
465
466  function end() {
467    if (!isDown) return;
468    isDown = false;
469    nav.classList.remove("is-dragging");
470    dragging = false;
471
472    if (capturedId !== null && nav.releasePointerCapture) {
473      try { nav.releasePointerCapture(capturedId); } catch (_) {}
474    }
475    capturedId = null;
476
477    if (typeof scheduleUpdate === "function") scheduleUpdate();
478  }
479
480  nav.addEventListener("pointerup", end);
481  nav.addEventListener("pointercancel", end);
482
483  // niente pointerleave: su alcuni browser può “chiudere” mentre ti muovi fuori di 1px
484  // nav.addEventListener("pointerleave", end);
485
486  nav.addEventListener("click", function (e) {
487    if (!moved) return;
488    e.preventDefault();
489    e.stopPropagation();
490    moved = false;
491  }, true);
492}
493
494
495
496
497    // ------------------------------------------------------------
498    // MENU HEADER SCROLL + FADE
499    // - se scrolla: menu a sinistra (via .is-scrollable)
500    // - fade: classi .has-left / .has-right sul wrapper .nav-fade
501    // - supporto a resize tardivi (skin adv) con ResizeObserver + recheck breve
502    // ------------------------------------------------------------
503
504
505
506	function initHeaderMenuFade() {
507	  var section = document.querySelector(".main-menu");
508	  if (!section) return;
509
510	  var nav = section.querySelector(".live-main-menu-container");
511	  if (!nav) return;
512
513	  // wrapper
514	  var wrap = section.querySelector(".nav-fade");
515	  if (!wrap) {
516		wrap = document.createElement("div");
517		wrap.className = "nav-fade nav-fade--menu";
518		nav.parentNode.insertBefore(wrap, nav);
519		wrap.appendChild(nav);
520	  }
521
522	  var shell = document.querySelector(".lnv-shell");
523
524	  var rafId = null;
525	  function schedule() {
526		if (rafId) return;
527		rafId = requestAnimationFrame(function () {
528		  rafId = null;
529		  update();
530		});
531	  }
532
533	  function update() {
534		var max = nav.scrollWidth - nav.clientWidth;
535		var x = nav.scrollLeft;
536		var scrollable = max > 1;
537
538		nav.classList.toggle("is-scrollable", scrollable);
539		wrap.classList.toggle("has-left", scrollable && x > 1);
540		wrap.classList.toggle("has-right", scrollable && x < max - 1);
541	  }
542
543	  // ✅ ATTACCA DRAG QUI (con update fade mentre trascini)
544	  enableHeaderMenuDrag(nav, schedule);
545
546	  // prima valutazione
547	  schedule();
548
549	  nav.addEventListener("scroll", schedule, { passive: true });
550	  window.addEventListener("resize", schedule);
551	  window.addEventListener("load", schedule);
552
553	  if ("ResizeObserver" in window) {
554		var ro = new ResizeObserver(function () { schedule(); });
555		ro.observe(nav);
556		ro.observe(wrap);
557		if (shell) ro.observe(shell);
558	  }
559
560	  if (document.fonts && document.fonts.ready && typeof document.fonts.ready.then === "function") {
561		document.fonts.ready.then(schedule).catch(function () {});
562	  }
563
564	  var tries = 0;
565	  var t = setInterval(function () {
566		tries++;
567		schedule();
568		if (tries >= 20) clearInterval(t);
569	  }, 100);
570	}
571
572
573    initHeaderMenuFade();
574  } catch (e) {
575    console.error("[live.js] fatal error:", e);
576  }
577});

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.