PageSourceSearch

https://www.callbell.eu/assets/js/common.js

js callbell.eu collected 2026-09-24 18:33:38 UTC 16,116 bytes, 521 lines download raw bytes

1(function ($) {
2  $(document).ready(function () {
3    var user_agent = navigator.userAgent;
4    var is_opera_edge;
5    var browser =
6      user_agent.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))/i) ||
7      [];
8    var browser_name = "";
9    var browser_class = "";
10    if (/trident/i.test(browser[0])) {
11      browser_name = "ie";
12    } else if (browser[0] === "Chrome") {
13      is_opera_edge = user_agent.match(/\b(OPR|Edge)/);
14      if (is_opera_edge !== null) {
15        browser_name = is_opera_edge[0].replace("OPR", "opera");
16      }
17    }
18    if ("" === browser_name) {
19      browser_name = "" !== browser[0] ? browser[0] : navigator.appName;
20    }
21    browser_name = browser_name.toLowerCase();
22    switch (browser_name) {
23      case "msie":
24        browser_class = "ie";
25        break;
26      case "firefox":
27        browser_class = "gecko";
28        break;
29      default:
30        browser_class = browser_name;
31        break;
32    }
33    if (user_agent.match(/iPhone/)) {
34      browser_class += " iphone";
35    }
36    $("body").addClass(browser_class);
37  });
38})(jQuery);
39
40(function () {
41  function getQueryParam(t, e) {
42    var r = t.split("?")[1];
43    if (!r) return null;
44    for (var i = r.split("&"), n = 0; n < i.length; n++) {
45      var u = i[n].split("=");
46      if (u[0] === e) return decodeURIComponent(u[1]);
47    }
48    return null;
49  }
50
51  function getCookie(t) {
52    for (
53      var e = t + "=", r = document.cookie.split(";"), i = 0;
54      i < r.length;
55      i++
56    ) {
57      var n = r[i].trim();
58      if (0 === n.indexOf(e)) return n.substring(e.length, n.length);
59    }
60    return null;
61  }
62
63  function setCookie(t, e, r) {
64    var i = "";
65    if (r) {
66      var n = new Date();
67      n.setTime(n.getTime() + 864e5 * r);
68      i = "; expires=" + n.toUTCString();
69    }
70    document.cookie = t + "=" + (e || "") + i + "; domain=callbell.eu; path=/";
71  }
72
73  function storeUtmParameters() {
74    if (!getCookie("_callbell_utm")) {
75      var trackingParams = [
76        "utm_source",
77        "utm_medium",
78        "utm_campaign",
79        "utm_content",
80        "utm_id",
81        "utm_term",
82        "utm_device",
83        "utm_adgroup",
84        "utm_location",
85        "utm_matchtype",
86        "utm_network",
87        "utm_agtype",
88        "gad_source",
89        "gclid",
90      ];
91
92      var data = {};
93
94      // Collect UTM & tracking params
95      for (var r = 0; r < trackingParams.length; r++) {
96        var val = getQueryParam(window.location.href, trackingParams[r]);
97        if (val) data[trackingParams[r]] = val;
98      }
99
100      // Add first landing URL and referrer
101      data["first_landing_url"] = window.location.href;
102      data["first_referrer"] = document.referrer || "";
103
104      if (Object.keys(data).length > 0) {
105        setCookie("_callbell_utm", btoa(JSON.stringify(data)), 30);
106      }
107    }
108  }
109
110  storeUtmParameters();
111})();
112
113(function () {
114  var url = window.location.href.split("#")[0];
115  var headline = document.querySelector("h1")?.innerText || document.title;
116  var description =
117    document.querySelector('meta[name="description"]')?.content || "";
118  var image =
119    document.querySelector('meta[property="og:image"]')?.content || "";
120  var lang = document.documentElement.lang || "en";
121
122  function normalizeUrl(path) {
123    if (!path) return "";
124    return path.startsWith("http") ? path : `https://www.callbell.eu${path}`;
125  }
126
127  var isBlogPost = !!document.querySelector(
128    'meta[property="article:published_time"]'
129  );
130
131  var graph = [
132    {
133      "@type": "WebSite",
134      "@id": "https://www.callbell.eu/#website",
135      url: "https://www.callbell.eu",
136      name: "Callbell",
137      description:
138        "Omnichannel customer communication platform for WhatsApp, Messenger, Instagram, Telegram & TikTok",
139      potentialAction: {
140        "@type": "SearchAction",
141        target: {
142          "@type": "EntryPoint",
143          urlTemplate: "https://www.callbell.eu/en/?s={search_term_string}",
144        },
145        "query-input": "required name=search_term_string",
146      },
147      inLanguage: ["en", "es", "fr", "it", "pt"],
148    },
149    {
150      "@type": "Organization",
151      "@id": "https://www.callbell.eu/#organization",
152      name: "Callbell",
153      description:
154        "Callbell is a SaaS platform providing omnichannel customer communication solutions via messaging apps such as WhatsApp, Facebook Messenger, Instagram, Telegram, and TikTok.",
155      legalName: "Callbell S.A.S.",
156      url: "https://www.callbell.eu",
157      logo: {
158        "@type": "ImageObject",
159        url: "https://www.callbell.eu/assets/uploads/2023/12/callbell-logo.svg",
160      },
161      foundingDate: "2019",
162      founders: [
163        {
164          "@type": "Person",
165          name: "Carlo Morandi",
166          url: "https://www.linkedin.com/in/morandicarlo",
167        },
168        {
169          "@type": "Person",
170          name: "Gianluca Bargelli",
171          url: "https://www.linkedin.com/in/gianlucabargelli",
172        },
173      ],
174      address: {
175        "@type": "PostalAddress",
176        streetAddress: "102, Avenue des Champs-Elysées",
177        addressLocality: "Paris",
178        addressRegion: "Île-de-France",
179        postalCode: "75000",
180        addressCountry: "FR",
181      },
182      contactPoint: {
183        "@type": "ContactPoint",
184        contactType: "customer support",
185        email: "[email protected]",
186        url: "https://www.callbell.eu/calendly",
187        telephone: "+31-97058018227",
188        availableLanguage: [
189          "English",
190          "Spanish",
191          "French",
192          "Italian",
193          "Portuguese",
194        ],
195      },
196      sameAs: [
197        "https://www.facebook.com/callbellplatform/",
198        "https://www.x.com/callbellapp",
199        "https://www.instagram.com/callbellchat/",
200        "https://www.linkedin.com/company/callbellchat",
201        "https://www.youtube.com/channel/UCaZ7WdKIV3BhDDfm6KCzrkQ",
202        "https://www.tiktok.com/@callbelloficial",
203      ],
204    },
205  ];
206
207  if (isBlogPost) {
208    var author =
209      document.querySelector(".saboxplugin-authorname").textContent ||
210      "Callbell Team";
211    var authorUrl = document
212      .querySelector(".saboxplugin-socials")
213      .querySelector("a").href;
214    var published =
215      document.querySelector('meta[property="article:published_time"]')
216        ?.content || "";
217    var modified =
218      document.querySelector('meta[property="article:modified_time"]')
219        ?.content || published;
220
221    graph.push({
222      "@type": "BlogPosting",
223      "@id": url + "#article",
224      mainEntityOfPage: { "@type": "WebPage", "@id": url },
225      url: url,
226      headline: headline,
227      description: description,
228      author: { "@type": "Person", name: author, url: authorUrl },
229      publisher: { "@id": "https://www.callbell.eu/#organization" },
230      inLanguage: lang,
231      image: { "@type": "ImageObject", url: normalizeUrl(image) },
232      datePublished: published,
233      dateModified: modified,
234    });
235  } else {
236    graph.push({
237      "@type": "WebPage",
238      "@id": url + "#webpage",
239      url: url,
240      name: headline,
241      description: description,
242      inLanguage: lang,
243      isPartOf: { "@id": "https://www.callbell.eu/#website" },
244      primaryImageOfPage: { "@type": "ImageObject", url: normalizeUrl(image) },
245    });
246  }
247
248  const structuredData = {
249    "@context": "https://schema.org",
250    "@graph": graph,
251  };
252
253  var script = document.createElement("script");
254  script.type = "application/ld+json";
255  script.text = JSON.stringify(structuredData, null, 2);
256  document.head.appendChild(script);
257})();
258
259document.addEventListener("DOMContentLoaded", function () {
260  // Responsive Zoom
261  function adjustBodyZoom() {
262    let screenWidth = document.documentElement.clientWidth;
263    let browserZoomLevel =
264      1 / Math.round((window.innerWidth / window.outerWidth) * 100);
265
266    let zoomLevel;
267
268    if (screenWidth <= 575) {
269      zoomLevel = screenWidth / 550;
270    } else if (screenWidth <= 980) {
271      zoomLevel = screenWidth / 1150;
272    } else {
273      zoomLevel = screenWidth / 1850;
274    }
275
276    document.body.style.zoom = zoomLevel / (1 / (browserZoomLevel / 0.01));
277  }
278
279  window.addEventListener("load", adjustBodyZoom); // Run adjustBodyZoom when everything is loaded
280  window.addEventListener("resize", adjustBodyZoom);
281
282  // Header & Footer paths
283  const headerPaths = {
284    en: "/assets/shared/header/en-header.html",
285    es: "/assets/shared/header/es-header.html",
286    fr: "/assets/shared/header/fr-header.html",
287    it: "/assets/shared/header/it-header.html",
288    pt: "/assets/shared/header/pt-header.html",
289  };
290
291  const footerPaths = {
292    en: "/assets/shared/footer/en-footer.html",
293    es: "/assets/shared/footer/es-footer.html",
294    fr: "/assets/shared/footer/fr-footer.html",
295    it: "/assets/shared/footer/it-footer.html",
296    pt: "/assets/shared/footer/pt-footer.html",
297  };
298
299  const fullLanguage = document.documentElement.lang || "en";
300  const languageCode = fullLanguage.split("-")[0].toLowerCase();
301
302  // Load header and footer based on language
303  const headerPath = headerPaths[languageCode] || headerPaths["en"];
304  const footerPath = footerPaths[languageCode] || footerPaths["en"];
305
306  // Function to load HTML into a specific container
307  function loadHTML(path, containerSelector) {
308    fetch(path)
309      .then((response) => {
310        if (!response.ok) {
311          throw new Error(`Failed to load ${path}: ${response.statusText}`);
312        }
313        return response.text();
314      })
315      .then((html) => {
316        document.querySelector(containerSelector).innerHTML = html;
317      })
318      .catch((error) => {
319        console.error(`Error loading the content from ${path}:`, error);
320      });
321  }
322
323  // Load header and footer
324  loadHTML(headerPath, "header");
325  loadHTML(footerPath, "footer");
326
327  // Mobile Header (delayed setup to ensure the header/footer are loaded)
328  setTimeout(() => {
329    const mobileMenuToggle = document.querySelector(".mobile_menu_bar_toggle");
330    const mobileMenu = document.getElementById("mobile_menu");
331    const mobileNav = document.querySelector(".mobile_nav");
332
333    if (mobileMenuToggle && mobileMenu) {
334      mobileMenuToggle.addEventListener("click", function () {
335        mobileNav.classList.toggle("closed");
336        mobileMenu.style.display = mobileNav.classList.contains("closed")
337          ? "none"
338          : "block";
339      });
340
341      function setupParentItemEvents() {
342        const parentItems = mobileMenu.querySelectorAll(
343          ".menu-item-has-children"
344        );
345
346        parentItems.forEach(function (parentItem) {
347          const submenu = parentItem.querySelector(".sub-menu");
348          const anchor = parentItem.querySelector("a");
349
350          anchor.addEventListener("click", function (e) {
351            e.preventDefault();
352            const isVisible = submenu.classList.contains("opened");
353            submenu.classList.toggle("opened", !isVisible); // Toggle 'open' class
354
355            // Close other open submenus
356            parentItems.forEach(function (otherParentItem) {
357              if (otherParentItem !== parentItem) {
358                const otherSubmenu = otherParentItem.querySelector(".sub-menu");
359                if (otherSubmenu) {
360                  otherSubmenu.classList.remove("opened"); // Close other submenus
361                }
362              }
363            });
364          });
365        });
366      }
367
368      setupParentItemEvents();
369    }
370  }, 1000);
371
372  // Initialize dropdown after header/footer are loaded
373  window.addEventListener("load", initializeDropdown);
374
375  function initializeDropdown() {
376    const dropdownBtn = document.getElementById("dropdownBtn");
377    const dropdownMenu = document.getElementById("dropdownMenu");
378
379    const aiDropdownBtn = document.getElementById("aiDropdownBtn");
380    const aiDropdownMenu = document.getElementById("aiDropdownMenu");
381
382    const flagIcons = {
383      en: "/assets/uploads/icons/en-lang-icon.svg",
384      fr: "/assets/uploads/icons/fr-lang-icon.svg",
385      es: "/assets/uploads/icons/es-lang-icon.svg",
386      it: "/assets/uploads/icons/it-lang-icon.svg",
387      pt: "/assets/uploads/icons/pt-lang-icon.svg",
388    };
389
390    const currentUrl = new URL(window.location.href);
391    let currentLang = currentUrl.pathname.split("/")[1] || "en";
392
393    // Setup Language Dropdown
394    if (dropdownBtn && dropdownMenu) {
395      dropdownBtn.textContent = getLanguageName(currentLang);
396      dropdownBtn.style.backgroundImage = "url(" + flagIcons[currentLang] + ")";
397
398      const alternateLinks = document.querySelectorAll('link[rel="alternate"]');
399      alternateLinks.forEach(function (link) {
400        const hreflang = link.getAttribute("hreflang");
401        const href = new URL(link.getAttribute("href"), currentUrl.origin).href;
402
403        if (hreflang !== currentLang) {
404          const optionDiv = document.createElement("div");
405          const img = document.createElement("img");
406          const p = document.createElement("p");
407
408          img.src = flagIcons[hreflang] || "";
409          p.textContent = getLanguageName(hreflang);
410
411          optionDiv.appendChild(img);
412          optionDiv.appendChild(p);
413
414          optionDiv.addEventListener("click", function () {
415            window.location.href = href;
416          });
417
418          dropdownMenu.appendChild(optionDiv);
419        }
420      });
421
422      dropdownBtn.addEventListener("click", function (e) {
423        e.stopPropagation();
424        dropdownMenu.style.display =
425          dropdownMenu.style.display === "block" ? "none" : "block";
426        // Close AI dropdown if open
427        if (aiDropdownMenu) {
428          aiDropdownMenu.style.display = "none";
429        }
430      });
431
432      // Close dropdown when clicking outside
433      window.addEventListener("click", function (event) {
434        if (
435          !event.target.closest(".custom-dropdown:not(.ai-custom-dropdown)")
436        ) {
437          dropdownMenu.style.display = "none";
438        }
439      });
440    }
441
442    if (aiDropdownBtn && aiDropdownMenu) {
443      aiDropdownBtn.addEventListener("click", function (e) {
444        e.stopPropagation();
445        aiDropdownMenu.style.display =
446          aiDropdownMenu.style.display === "block" ? "none" : "block";
447        if (dropdownMenu) {
448          dropdownMenu.style.display = "none";
449        }
450      });
451
452      window.addEventListener("click", function (event) {
453        if (!event.target.closest(".ai-custom-dropdown")) {
454          aiDropdownMenu.style.display = "none";
455        }
456      });
457
458      const aiLinks = aiDropdownMenu.querySelectorAll(".ai-dropdown-link");
459      aiLinks.forEach((link) => {
460        link.addEventListener("click", function (e) {
461          aiDropdownMenu.style.display = "none";
462        });
463      });
464    }
465  }
466
467  function getLanguageName(code) {
468    const languages = {
469      en: "English",
470      fr: "Français",
471      es: "Español",
472      it: "Italiano",
473      pt: "Português",
474    };
475    return languages[code] || code;
476  }
477});
478
479// Flying Scripts
480const loadScriptsTimer = setTimeout(loadScripts, 8 * 1000);
481const userInteractionEvents = [
482  "mouseover",
483  "keydown",
484  "touchstart",
485  "touchmove",
486  "wheel",
487];
488userInteractionEvents.forEach(function (event) {
489  window.addEventListener(event, triggerScriptLoader, { passive: !0 });
490});
491function triggerScriptLoader() {
492  loadScripts();
493  clearTimeout(loadScriptsTimer);
494  userInteractionEvents.forEach(function (event) {
495    window.removeEventListener(event, triggerScriptLoader, { passive: !0 });
496  });
497}
498function loadScripts() {
499  document
500    .querySelectorAll("script[data-type='lazy']")
501    .forEach(function (elem) {
502      elem.setAttribute("src", elem.getAttribute("data-src"));
503    });
504}
505
506// Toggle funtion
507const toggleTitles = document.querySelectorAll(".et_pb_toggle_item");
508
509toggleTitles.forEach((toggleTitle) => {
510  toggleTitle.addEventListener("click", (e) => {
511    e.stopImmediatePropagation();
512
513    if (toggleTitle.classList.contains("et_pb_toggle_close")) {
514      toggleTitle.classList.remove("et_pb_toggle_close");
515      toggleTitle.classList.add("et_pb_toggle_open");
516    } else {
517      toggleTitle.classList.remove("et_pb_toggle_open");
518      toggleTitle.classList.add("et_pb_toggle_close");
519    }
520  });
521});

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.