PageSourceSearch

https://www.motorfinanceonline.com/wp-content/themes/goodlife-wp-B2B/assets/js/sep-22-ui.js?ver=1.3

js motorfinanceonline.com collected 2026-09-26 01:38:37 UTC 48,751 bytes, 1,462 lines download raw bytes

1"use strict";
2
3///////////////////////////////////////
4// Debugging
5///////////////////////////////////////
6const debugSep22UI = (
7  functionName = "No function name entered. Use the error stack above",
8) => {
9  const err = new Error();
10  if (debugSep22Mode === true)
11    alert(`
12
13    ----
14    Call from:
15    ${err.stack}
16
17    ----
18
19    Optional nice name (of function (manually typed)):
20
21    ${functionName}
22
23    `);
24  else return;
25};
26let debugSep22Mode = false;
27
28///////////////////////////////////////
29// Helper functions and values
30///////////////////////////////////////
31
32let isMobile = false;
33if (/Mobi|Android/i.test(navigator.userAgent)) isMobile = true;
34
35// Get the site name from the URL to use elsewhere
36class urlHelper {
37  constructor(url) {
38    this.url = url;
39  }
40  siteName() {
41    if (this.url.includes("localhost")) return "pharmaceutal-technology";
42    else if (this.url.includes("127.0.0.1")) return "pharmaceutal-technology";
43    else return toString([...this.url].splice(this.url.indexOf("//", ".com/")));
44  }
45  restartSplitTest() {
46    if (this.url.includes("?=restart-split-test")) {
47      localStorage.removeItem("stopSplitTest");
48      localStorage.removeItem("showSplitTestVariant");
49    }
50  }
51  stopSplitTest() {
52    if (this.url.includes("?=stop-split-test"))
53      localStorage.setItem("stopSplitTest");
54  }
55}
56const urlHelpers = new urlHelper(window.location.href);
57urlHelpers.restartSplitTest();
58urlHelpers.stopSplitTest();
59
60// Burger menu toggle
61const burgerMenuBtn = document.querySelector(".menu-button");
62const burgerMenuBg = document.querySelector(".menu-bg");
63const toggleBurgerMenu = function () {
64  document.body.classList.toggle("burger-menu-open");
65  document.body.classList.toggle("show-menu-bg");
66};
67if (burgerMenuBtn && burgerMenuBg) {
68  burgerMenuBtn.addEventListener("click", toggleBurgerMenu);
69  burgerMenuBg.addEventListener("click", toggleBurgerMenu);
70  window.addEventListener("keyup", (e) => {
71    if (e.key !== "Escape") return;
72    e.key === "Escape" &&
73      document.body.classList.contains("burger-menu-open") &&
74      toggleBurgerMenu();
75  });
76}
77
78// Make the previous sibling have an active class
79const burgerMenuCheckbox = document.querySelectorAll(
80  ".site-header .burger-menu section ul li input",
81);
82const activePrevious = (element) => {
83  element.forEach((el) => {
84    el.addEventListener("click", function () {
85      el.previousSibling.classList.toggle("active");
86    });
87  });
88};
89if (burgerMenuBtn) activePrevious(burgerMenuCheckbox);
90
91// Make the width of the buger menu line up with the toggle button right edge
92const burgerMenu = document.querySelector(".burger-menu");
93const burgerMenuWidth = () => {
94  // Get the width of the content container
95  const gridContainerWidth = document.querySelector(
96    ".site-header .grid-container",
97  ).offsetWidth;
98
99  // Get the width from grid container left edge to right edge of toggle button
100  const widthToToggleRightEdge =
101    document.querySelector(".site-header .site-logo").offsetWidth +
102    document.querySelector(".site-header .menu-button").offsetWidth;
103
104  // Now get the whole screen width, take away the grid-container width and add the logo and menu toggle widths to get the position of the right edge of the toggle
105  if (window.innerWidth > 990) {
106    const burgerMenuWidth =
107      (window.innerWidth - gridContainerWidth) / 2 +
108      widthToToggleRightEdge +
109      40;
110    burgerMenu.style.width = `${burgerMenuWidth}px`;
111    burgerMenu.style.left = `${-1 * burgerMenuWidth}px`;
112  }
113};
114
115document.querySelector(".site-header .grid-container") && burgerMenuWidth();
116
117// Position burger menu directly below site header minus nav bars
118
119const navBar = document.querySelector(".nav-bar");
120const subNavBar = document.querySelector(".sub-nav-bar");
121const siteHeader = document.querySelector(".site-header");
122const bannerContainer = document.querySelector(".stream-item-above-header");
123let stickyHeaderState = false;
124const positionBurgerMenu = () => {
125  // debugSep22UI();
126  if (document.body.classList.contains("sticky-header")) {
127    // console.log('Sticky is on');
128    burgerMenu.style.top = `${siteHeader.getBoundingClientRect().bottom}px`;
129  } else {
130    // console.log('No sticky header');
131    if (navBar) {
132      burgerMenu.style.top = `${
133        (bannerContainer ? bannerContainer.offsetHeight : "") +
134        siteHeader.offsetHeight -
135        navBar.offsetHeight -
136        (subNavBar ? subNavBar.offsetHeight : 0) -
137        window.pageYOffset
138      }px`;
139      burgerMenuBg.style.top = `${
140        (bannerContainer ? bannerContainer.offsetHeight : "") +
141        siteHeader.offsetHeight -
142        navBar.offsetHeight -
143        (subNavBar ? subNavBar.offsetHeight : 0) -
144        window.pageYOffset
145      }px`;
146    } else {
147      burgerMenu.style.top = `${
148        (bannerContainer ? bannerContainer.offsetHeight : "") +
149        siteHeader.offsetHeight -
150        window.pageYOffset
151      }px`;
152      burgerMenuBg.style.top = `${
153        (bannerContainer ? bannerContainer.offsetHeight : "") +
154        siteHeader.offsetHeight -
155        window.pageYOffset
156      }px`;
157    }
158  }
159};
160if (burgerMenu) {
161  positionBurgerMenu();
162  document.addEventListener("scroll", positionBurgerMenu);
163  window.addEventListener("resize", positionBurgerMenu);
164}
165
166// Search toggle
167const newSearchEl = document.querySelector(".laptop-search");
168const newSearchBtn = document.querySelector(".search-button");
169const mewSearchBox = document.querySelector(".search-box");
170let searchStatus = "closed";
171
172if (newSearchBtn) {
173  newSearchBtn.addEventListener("click", function () {
174    newSearchEl.classList.add("laptop-search-open");
175    newSearchBtn.classList.add("hidden");
176    mewSearchBox.focus();
177    searchStatus = "open";
178  });
179  document.addEventListener("click", function (e) {
180    if ((searchStatus = "open")) {
181      if (e.target.closest(".laptop-search")) return;
182      if (e.target.closest(".search-button")) return;
183
184      // On the search results page do not close the search box if the user clicks outside of it
185      if (!document.body.classList.contains("page-id-133094")) {
186        newSearchEl.classList.remove("laptop-search-open");
187        newSearchBtn.classList.remove("hidden");
188        searchStatus = "closed";
189      }
190    }
191  });
192  window.addEventListener("keyup", (e) => {
193    if (e.key !== "Escape") return;
194    e.key === "Escape" &&
195      newSearchEl.classList.contains("laptop-search-open") &&
196      newSearchEl.classList.remove("laptop-search-open");
197  });
198}
199
200// Horizontal scrolling subnav
201
202// Add the width of the breadcrumbs as margin to the left of the subCategories
203const breadcrumb = document.querySelector(".breadcrumb");
204const subCategories = document.querySelector(".subcategories");
205const subCatsUl = document.querySelector(".subcategories ul");
206const subCatsLis = document.querySelectorAll(".subcategories li");
207
208const setSubCategoriesMargin = () => {
209  debugSep22UI();
210  const breadcrumbWidth = breadcrumb.offsetWidth;
211  document.querySelector(".subcategories").style.marginLeft =
212    breadcrumbWidth + 24 + "px";
213  subCategories.classList.add("loaded");
214};
215if (breadcrumb)
216  window.addEventListener("DOMContentLoaded", setSubCategoriesMargin, false);
217
218const countChildrenWidths = (container, parent, children) => {
219  debugSep22UI();
220  const childrenWidth = [...children].reduce(
221    (acc, li) => acc + li.offsetWidth + 24,
222    0,
223  );
224  window.innerWidth < 900
225    ? (parent.style.width = childrenWidth + "px")
226    : (parent.style.width = childrenWidth + 100 + "px");
227  if (childrenWidth > container.offsetWidth)
228    document.body.classList.add("show-side-arrows");
229};
230if (subCategories) countChildrenWidths(subCategories, subCatsUl, subCatsLis);
231
232const arrowRight = document.querySelector(".arrow-right");
233const arrowLeft = document.querySelector(".arrow-left");
234const ulLastChild = document.querySelector(".subcategories ul li:last-child");
235const subNavInner = document.querySelector(".sub-nav-inner");
236
237if (subNavInner) {
238  let marginLeft = 0;
239  const subCatsUlRightEdge = subCatsUl.getBoundingClientRect().right;
240  const subCatsUlLeftEdge = subCatsUl.getBoundingClientRect().left;
241  const moveLeft = function () {
242    marginLeft -= 100;
243    if (window.innerWidth > 600) {
244      subCatsUl.style.marginLeft = marginLeft + "px";
245    } else {
246      subCategories.style.position = "static";
247      subNavInner.style.marginLeft = marginLeft + "px";
248      breadcrumb.style.marginLeft = marginLeft + "px";
249    }
250    let subCatsUlLastChildRightEdge = ulLastChild.getBoundingClientRect().right;
251    if (subCatsUlLastChildRightEdge - 70 <= subCatsUlRightEdge) {
252      arrowRight.style.display = "none";
253    }
254    let subCatsUlFirstChildLeftEdge = document
255      .querySelector(".subcategories ul li:first-child")
256      .getBoundingClientRect().left;
257    if (subCatsUlFirstChildLeftEdge - 70 < subCatsUlLeftEdge) {
258      arrowLeft.style.display = "block";
259    }
260  };
261
262  arrowRight.addEventListener("click", moveLeft);
263
264  const moveRight = function () {
265    marginLeft += 100;
266
267    if (window.innerWidth > 600) {
268      subCatsUl.style.marginLeft = marginLeft + "px";
269    } else {
270      if (breadcrumb.offsetLeft > 0) {
271        arrowLeft.style.display = "none";
272      }
273      subNavInner.style.marginLeft = marginLeft + "px";
274      breadcrumb.style.marginLeft = marginLeft + "px";
275    }
276
277    let subCatsUlLastChildRightEdge = ulLastChild.getBoundingClientRect().right;
278
279    if (subCatsUlLastChildRightEdge < subCatsUlRightEdge) {
280      arrowRight.style.display = "none";
281    }
282
283    let subCatsUlFirstChildLeftEdge = document
284      .querySelector(".subcategories ul li:first-child")
285      .getBoundingClientRect().left;
286
287    if (subCatsUlFirstChildLeftEdge > subCatsUlLeftEdge) {
288      arrowLeft.style.display = "none";
289    }
290
291    if (subCatsUlLastChildRightEdge - 70 > subCatsUlRightEdge) {
292      arrowRight.style.display = "block";
293    }
294  };
295  arrowLeft.addEventListener("click", moveRight);
296}
297
298// Sticky nav / Sticky header
299if (navBar) {
300  const navBarPos = navBar.getBoundingClientRect().top;
301  const scrollableElement = document.body;
302  const backToTopBtn = document.querySelector(".scrollTopBtn"); // this uses the same functionality to show when scrolling up
303  let lastScrollTop = 0; // pageYOffset || scrollTop;
304
305  const initialState = function () {
306    if (!document.body.classList.contains("burger-menu-open")) {
307      stickyHeaderState = false;
308      if (window.innerWidth > 992) {
309        navBar.classList.remove("sticky-nav");
310        if (subNavBar) subNavBar.classList.remove("sticky-nav");
311      } else {
312        scrollableElement.classList.remove("sticky-header");
313        scrollableElement.style.paddingTop = 0;
314      }
315    }
316    document.body.style.paddingTop = 0;
317    // document.body.classList.remove('scrolling-up');
318    // Back to top button
319    if (backToTopBtn) backToTopBtn.classList.remove("show");
320  };
321
322  const onScrollUp = function () {
323    let st = window.pageYOffset || document.documentElement.scrollTop;
324
325    const headerBannerContainer = document.querySelector(
326      ".stream-item-above-header",
327    );
328
329    // Scrolling down
330    if (st > lastScrollTop) {
331      // console.log('Scrolling down');
332      initialState();
333
334      // Scrolling up
335    } else {
336      // console.log('Scrolling up');
337      // In desktop only the nav bar is sticky
338      if (window.innerWidth > 992) {
339        stickyHeaderState = true;
340        navBar.classList.add("sticky-nav");
341
342        let bodyPadding = navBar.offsetHeight;
343        if (subNavBar) {
344          subNavBar.classList.add("sticky-nav");
345          bodyPadding = navBar.offsetHeight + subNavBar.offsetHeight;
346          // console.log(`bodyPadding = ${bodyPadding}`);
347        }
348        document.body.style.paddingTop = bodyPadding + "px";
349      } else {
350        stickyHeaderState = true;
351        // In mobile the whole header is sticky
352        scrollableElement.classList.add("sticky-header");
353        scrollableElement.style.paddingTop = siteHeader.offsetHeight + "px";
354      }
355      // Back to top button
356      if (backToTopBtn) backToTopBtn.classList.add("show");
357    }
358
359    // If we reach the top again go back to normal state
360    const siteHeaderHeight = headerBannerContainer
361      ? headerBannerContainer.offsetHeight + siteHeader.offsetHeight
362      : siteHeader.offsetHeight;
363    if (scrollY < navBarPos || window.scrollY < siteHeaderHeight) {
364      initialState();
365    }
366
367    lastScrollTop = st <= 0 ? 0 : st; // For Mobile or negative scrolling
368  };
369
370  window.addEventListener(
371    "scroll",
372    function () {
373      onScrollUp();
374    },
375    false,
376  );
377
378  // If the user leaves the window and comes back or resizes we revert to initial state
379  document.addEventListener("visibilitychange", initialState);
380  window.addEventListener("resize", initialState);
381}
382
383// Storefront enquiry modal
384const enquiryButton = document.querySelector(
385  ".storefront-heading-content .primary",
386);
387const enquiryForm = document.querySelector(".storefront-page .modal-full");
388const enquiryModalClose = document.querySelector("#close-trigger");
389const openEnquiryForm = () => {
390  document.body.classList.add("freeze-element");
391  enquiryForm.classList.add("open");
392  window.innerWidth > 900
393    ? (enquiryForm.style.top = enquiryForm.style.paddingBottom =
394        siteHeader.offsetHeight + "px")
395    : (enquiryForm.style.top = 0 + "px");
396};
397
398if (enquiryButton) {
399  enquiryButton.addEventListener("click", openEnquiryForm);
400  const closeEnquiryForm = () => {
401    enquiryForm.classList.remove("open");
402    document.body.classList.remove("freeze-element");
403  };
404  enquiryModalClose.addEventListener("click", () => {
405    closeEnquiryForm;
406  });
407  window.addEventListener("keyup", (e) => {
408    if (e.key !== "Escape") return;
409    e.key === "Escape" && closeEnquiryForm();
410  });
411}
412const enquiryFormSubmit = document.querySelector("#formSubmitBtn");
413const formSubmitButton = document.querySelector("#newsletterForm .button");
414if (enquiryFormSubmit)
415  enquiryFormSubmit.addEventListener("click", () =>
416    document.body.classList.remove("freeze-element"),
417  );
418if (formSubmitButton)
419  formSubmitButton.addEventListener("click", () =>
420    document.body.classList.remove("freeze-element"),
421  );
422
423// This should be combined with the above function and changed to async await with parameters for the await
424const limitAsyncText = (
425  selector,
426  characters,
427  revealText,
428  hideText,
429  extraElsToShowHide,
430  mobileOnly,
431  delay,
432) => {
433  debugSep22UI();
434
435  setTimeout(function () {
436    const container = document.querySelector(selector);
437    const containerText = container.textContent; // for counting characters
438
439    // Sometimes the excerpt has no paragraph element. Sometimes it has one and sometimes several. First check if it has one and if so select the first one
440    let firstPara =
441      container.firstElementChild && container.firstElementChild.tagName === "P"
442        ? document.querySelector(`${selector} p:first-child`)
443        : container;
444
445    let textSnippet =
446      firstPara.textContent.length < characters
447        ? firstPara.textContent
448        : containerText.slice(0, characters);
449
450    let textSnippetCut =
451      textSnippet.length < characters
452        ? textSnippet
453        : textSnippet.slice(0, textSnippet.lastIndexOf(" "));
454
455    const showHideText = () => {
456      debugSep22UI();
457      container.classList.add("hidden");
458
459      const textSnippetEl = document.createElement("p");
460      textSnippetEl.classList.add("whitepaper-header__excerpt--snippet");
461      textSnippetEl.textContent = textSnippetCut + "...";
462      container.after(textSnippetEl);
463
464      const readMore = document.createElement("p");
465      readMore.classList.add("read-more");
466      readMore.textContent = revealText;
467      textSnippetEl.after(readMore);
468
469      if (extraElsToShowHide) {
470        const elsToShowHide = document.querySelectorAll(extraElsToShowHide);
471        [...elsToShowHide].forEach((el) => (el.style.display = "none"));
472      }
473
474      let textLoaded = false;
475      const showText = (e) => {
476        e.preventDefault();
477
478        const elsToShowHide = extraElsToShowHide
479          ? document.querySelectorAll(extraElsToShowHide)
480          : "";
481
482        if (textLoaded == false) {
483          textSnippetEl.classList.add("hidden");
484          container.classList.remove("hidden");
485          readMore.textContent = hideText;
486          readMore.classList.add("read-less");
487
488          if (extraElsToShowHide)
489            [...elsToShowHide].forEach((el) => (el.style.display = "block"));
490
491          textLoaded = true;
492        } else {
493          textSnippetEl.classList.remove("hidden");
494          container.classList.add("hidden");
495          readMore.textContent = revealText;
496          readMore.classList.remove("read-less");
497
498          if (extraElsToShowHide)
499            [...elsToShowHide].forEach((el) => (el.style.display = "none"));
500
501          textLoaded = false;
502        }
503      };
504
505      readMore.addEventListener("click", showText);
506    };
507
508    if (mobileOnly) {
509      if (containerText.length > characters) mobileOnlyDisplay(showHideText);
510    } else {
511      if (containerText.length > characters) showHideText();
512    }
513  }, delay);
514};
515
516if (document.querySelector(".ai-answer-and-sources"))
517  limitAsyncText(
518    ".ai-answer",
519    215,
520    "Show complete answer",
521    "Show less",
522    [".source-articles"],
523    true,
524    7000,
525  );
526
527///////////////////////////////////////
528// Tabs -- used in storefront and magazine page
529///////////////////////////////////////
530
531// This is moved to a module now
532
533// const tabs = (navLisSelector, tabPanels, tabPanelsContainer) => {
534//   debugSep22UI();
535//   const tabsNavLi = document.querySelectorAll(navLisSelector);
536//   const tabPanel = document.querySelectorAll(tabPanels);
537//   tabsNavLi[0].classList.add("open-tab");
538//   tabPanel[0].classList.add("open-tab");
539
540//   // if someone clicks tabsNavLi[i], then open tabPanel[i]
541//   tabsNavLi.forEach(function (li, i) {
542//     li.addEventListener("click", function () {
543//       tabsNavLi.forEach((li) => li.classList.remove("open-tab"));
544//       tabPanel.forEach((div) => div.classList.remove("open-tab"));
545//       tabsNavLi[i].classList.add("open-tab");
546//       tabPanel[i].classList.add("open-tab");
547//     });
548//   });
549
550//   // Make sure they're all the same height
551//   const tabHeights = [...tabPanel].map((panel) => panel.offsetHeight);
552//   document.querySelector(tabPanelsContainer).style.height = `${Math.max(
553//     ...tabHeights
554//   )}px`;
555// };
556// if (document.querySelector(".tabs-navigation"))
557//   tabs(".tabs-nav li", ".tabs-content__panel");
558
559///////////////////////////////////////
560// Remove the empty elements added by backend team to make the website neater
561///////////////////////////////////////
562const removeEmptyElements = function (...elements) {
563  const els = document.querySelectorAll(elements);
564  els.forEach(function (el, i) {
565    if ((elements == "p" || elements == "li") && (elements.classList = "")) {
566      if (el.textContent.trim().length === 0) {
567        el.remove();
568        console.log(`Removed: ${el}`);
569      }
570    }
571  });
572};
573//document.addEventListener("click", removeEmptyElements("p"));
574
575// Projects filter toggle
576const projectFiltersToggle = document.querySelector(".btn-mobile-filters");
577const filters = document.querySelectorAll(".inline-filters-box .line-filter");
578const projectFilters = function () {
579  projectFiltersToggle.addEventListener("click", function () {
580    filters.forEach((el) => (el.style.display = "block"));
581  });
582};
583if (projectFiltersToggle) projectFilters();
584
585// Newsletter fix to hide inputs until modal is loaded
586const newsletterFormEl = document.querySelector("#newsletterForm");
587if (newsletterFormEl && !document.querySelector(".storefront-page")) {
588  const formGroups = document.querySelectorAll("#newsletterForm .form-group");
589  const formGroupsArr = Array.prototype.slice.call(formGroups);
590  const checkMarks = document.querySelectorAll(".tag-box-big-add .checkmark");
591  const emailField = document.querySelector("#checkEmail");
592  const modalCloseArrow = document.querySelector(".modal-close-arrow");
593
594  const showHideFields = () =>
595    formGroupsArr.map((fg, i) =>
596      i !== 0 ? (formGroups[i].style.opacity = 0) : "",
597    );
598
599  if (checkMarks)
600    checkMarks.forEach((check) =>
601      check.addEventListener("click", showHideFields),
602    );
603  if (emailField)
604    emailField.addEventListener("click", function () {
605      formGroupsArr.map((fg, i) => (formGroups[i].style.opacity = 1));
606    });
607
608  // Newsletter fix to make the modal not overflow out of the top of the screen when the iPhone keyboard is loaded: only on All Newsletter page
609  if (
610    emailField &&
611    document.querySelector(".newsletter-wrapper") &&
612    document.querySelector(".tag-box-wrapper")
613  ) {
614    emailField.addEventListener("focus", () => {
615      document.body.classList.add("freeze-element");
616      window.scrollTo(0, 0);
617    });
618    // window.addEventListener("resize", function () {
619    //   window.scrollTo(0, 0);
620    // });
621    if (modalCloseArrow)
622      modalCloseArrow.addEventListener("click", () =>
623        document.body.classList.remove("freeze-element"),
624      );
625  }
626}
627
628// Table with bar chart
629const barChartTable = document.querySelector(".bar-chart-table");
630const createBars = () => {
631  debugSep22UI();
632  const barCells = document.querySelectorAll(".bar-chart");
633  const barCellsArr = Array.from(barCells);
634  const barData = barCellsArr.map((el) =>
635    el.textContent.replace(/(\r\n|\n|\r)/gm, "").trim(),
636  );
637  // const descendingData = barData.sort((a, b) => (a + b));
638  const maxValue = Math.max(...barData);
639  barData.forEach((n, i) => {
640    const barNumEl = document.createElement("b");
641    barNumEl.textContent = n;
642    barCells[i].textContent = "";
643    barCells[i].append(barNumEl);
644    const bar = document.createElement("span");
645    barCells[i].prepend(bar);
646    const barWidth = (n / maxValue) * 100;
647    bar.style.width = barWidth + "%";
648    barNumEl.style.left = barWidth + "%";
649    if (barWidth > 50) {
650      barNumEl.style.marginLeft = "-30px";
651      barNumEl.style.color = "white";
652    }
653  });
654};
655if (barChartTable) createBars();
656
657///////////////////////////////////////
658// Chart / Polls loading animation
659///////////////////////////////////////
660class gdCharts {
661  chart = document.createElement("div");
662  bars = document.createElement("ul");
663
664  constructor(type, variant, values, container, animation, showNumbers) {
665    this.type = type;
666    this.variant = variant;
667    this.values = values;
668    this.container = container;
669    this.animation = animation;
670    this.showNumbers = showNumbers;
671    this.total = values.reduce(
672      (cumulative, current) => cumulative + current,
673      0,
674    );
675    this.maxValue = Math.max(...values);
676  }
677  createChart() {
678    this.chart.classList.add("chart", this.type, this.variant);
679    const containerEl = document.querySelector(this.container);
680    containerEl.insertAdjacentElement("beforeend", this.chart);
681    this.chart.insertAdjacentElement("afterbegin", this.bars);
682    return this;
683  }
684  createBars() {
685    this.values.forEach((value, i, arr) => {
686      const bar = document.createElement("li");
687      const barPercent = (value / this.maxValue) * 100;
688
689      // Create the height or width of the bars
690      this.variant === "horizontal"
691        ? (bar.style.width = `${barPercent}% `)
692        : (bar.style.height = `${barPercent}% `);
693
694      // If the bars are vertical, make them span the full width of the chart
695      if (this.variant === "vertical")
696        bar.style.width = `${100 / this.values.length}% `;
697
698      this.bars.insertAdjacentElement("afterbegin", bar);
699      if (this.showNumbers) bar.textContent = value;
700    });
701    this.chart.insertAdjacentElement("afterbegin", this.bars);
702    return this;
703  }
704  useAsLoadingAnimation() {
705    this.chart.classList.add("loading-animation");
706    const loadingText = document.createElement("p");
707    loadingText.classList.add("loading-text");
708    const loadingLetters = "Loading...";
709    [...loadingLetters].forEach((letter) => {
710      const span = document.createElement("span");
711      span.textContent = letter;
712      loadingText.insertAdjacentElement("beforeend", span);
713      setInterval(function () {
714        span.classList.toggle("show");
715      }, 1200);
716    });
717    this.chart.insertAdjacentElement("beforeend", loadingText);
718    window.addEventListener("load", function () {
719      this.setTimeout(function () {
720        document.querySelector(".loading-animation").remove();
721      }, 2000);
722    });
723    return this;
724  }
725}
726
727///////////////////////////////////////
728// REQUIRED FORM FIELD ERROR MESSAGE - NOT VALIDATION. Validation is in custom_newsletter.js
729///////////////////////////////////////
730
731const selects = document.querySelectorAll(
732  "#newsletterForm select[aria-required=true",
733);
734const textInputs = document.querySelectorAll(
735  "#newsletterForm input[aria-required=true]",
736);
737const submitButton = document.querySelector("#submitButton");
738
739const displayErrors = (elements) => {
740  [...elements].forEach((element) => {
741    const errorEl = element.nextElementSibling;
742
743    if (element.value === "0" || element.value === "") {
744      element.classList.add("error");
745      const errorDetail =
746        element.tagName === "INPUT"
747          ? element.placeholder
748          : element.options[0].textContent;
749      if (errorEl) {
750        errorEl.textContent = `Please enter a ${errorDetail} `;
751      }
752    } else {
753      element.classList.remove("error");
754      if (errorEl) {
755        errorEl.textContent = "";
756      }
757    }
758  });
759};
760if (newsletterFormEl && submitButton) {
761  submitButton.addEventListener("click", (e) => {
762    displayErrors(selects);
763    displayErrors(textInputs);
764  });
765  newsletterFormEl.addEventListener("change", (e) => {
766    displayErrors(textInputs);
767    displayErrors(selects);
768  });
769}
770
771const searchResultsHeadings = document.querySelectorAll("#rso h3");
772[...searchResultsHeadings].forEach((heading, i) => {
773  if (i === 0) {
774    heading.style.borderTop = "solid 1px black";
775    heading.style.color = "red";
776  } else {
777    heading.style.color = "green";
778  }
779});
780
781///////////////////////////////////////
782// Premium Insights
783///////////////////////////////////////
784
785// Scrollbar padding on search page and premium insights
786const searchWrappers = document.querySelectorAll(".search-wrapper");
787const searchWrapperUls = document.querySelectorAll(
788  ".search-wrapper ul.wpsolr_facet_scroll",
789);
790const scrollBarPadding = function (parent, padding) {
791  debugSep22UI();
792  [...parent].forEach((el) => {
793    const elsTotalHeight = [...el.children].reduce(
794      (acc, cur) => acc + cur.offsetHeight,
795      0,
796    );
797    const scrollShowing = () => {
798      el.style.paddingRight = padding;
799      el.style.overflow = "auto";
800    };
801    elsTotalHeight > el.offsetHeight
802      ? scrollShowing()
803      : (el.style.paddingRight = "0");
804  });
805};
806
807if (searchWrapperUls[0]) {
808  scrollBarPadding(searchWrapperUls, "12px");
809  const searchFilters = document.querySelectorAll(
810    '.search-wrapper input[type="search"]',
811  );
812
813  [...searchFilters].forEach((input) =>
814    input.addEventListener("keyup", () =>
815      scrollBarPadding(searchWrapperUls, "12px"),
816    ),
817  );
818}
819
820const searchFiltersOpen = document.querySelector(".search-filters-btn");
821const searchFiltersContainer = document.querySelector(
822  ".search-filter-container",
823);
824const searchFiltersClose = document.querySelector(".search-filter-btn--close");
825
826if (searchFiltersContainer) {
827  const openFilters = (e) => {
828    e.preventDefault();
829    searchFiltersContainer.classList.add("open-filters");
830    searchFiltersContainer.style.display = "block";
831  };
832  const closeFilters = (e) => {
833    e.preventDefault();
834    searchFiltersContainer.classList.remove("open-filters");
835    searchFiltersContainer.style.display = "none";
836  };
837  searchFiltersClose.addEventListener("click", function (e) {
838    closeFilters(e);
839    // e.preventDefault();
840    // searchFiltersContainer.classList.remove("open-filters");
841    // searchFiltersContainer.style.display = "none";
842  });
843  searchFiltersOpen.addEventListener("click", function (e) {
844    openFilters(e);
845  });
846  // window.addEventListener("resize", function () {
847  //     if (window.innerWidth > 990) openFilters(e);
848  // });
849}
850
851const sortCheckedFilters = (elements) => {
852  [...elements].forEach((ul) => {
853    const moveCheckedToTop = (target, className, firstEl) => {
854      if (target.classList.contains(className)) {
855        firstEl.insertAdjacentElement("beforebegin", target.parentElement);
856      }
857    };
858
859    const checkBoxes = ul.querySelectorAll(".select_opt");
860    const firstElement = ul.querySelector("li");
861
862    checkBoxes.forEach((checkbox) =>
863      moveCheckedToTop(checkbox, "checked", firstElement),
864    );
865
866    checkBoxes.forEach((checkbox) => {
867      moveCheckedToTop(checkbox);
868      const options = {
869        attributes: true,
870      };
871      function callback(mutationList, observer) {
872        mutationList.forEach(function (mutation) {
873          if (
874            mutation.type === "attributes" &&
875            mutation.attributeName === "class"
876          ) {
877            if (mutation.target.classList.contains("checked"))
878              moveCheckedToTop(mutation.target);
879          }
880        });
881      }
882
883      const observer = new MutationObserver(callback);
884      observer.observe(checkbox, options);
885    });
886  });
887};
888
889// if (uls[0]) {
890//   sortCheckedFilters(uls);
891
892//   const waitForElm = (selector) => {
893//     return new Promise(resolve => {
894//       if (document.querySelector(selector)) {
895//         return resolve(document.querySelector(selector));
896//         sortCheckedFilters(uls);
897//       }
898
899//       const observer = new MutationObserver(mutations => {
900//         if (document.querySelector(selector)) {
901//           resolve(document.querySelector(selector));
902//           sortCheckedFilters(uls);
903//           observer.disconnect();
904//         }
905//       });
906
907//       observer.observe(document.body, {
908//         childList: true,
909//         subtree: true
910//       });
911//     });
912//   }
913
914//   const elm = await waitForElm('.results-by-facets article');
915
916// }
917
918const onlyFirstUlOpen = () =>
919  [...searchWrapperUls].filter((el, i) =>
920    i === 0 ? (el.style.display = "block") : (el.style.display = "none"),
921  );
922
923const toggleSearchFilter = () => {
924  [...searchWrappers].forEach((el, i) => {
925    if (i > 0) {
926      el.addEventListener("click", (e) => {
927        if (e.target.classList.contains("search-filter-section--dropdown")) {
928          [...el.children].forEach((el) => {
929            if (el.tagName === "UL") {
930              el.style.display === "none"
931                ? (el.style.display = "block")
932                : (el.style.display = "none");
933
934              return;
935            }
936          });
937        }
938      });
939    }
940  });
941};
942
943if (searchWrapperUls[1]) {
944  // onlyFirstUlOpen();
945  //toggleSearchFilter();
946}
947
948///////////////////////////////////////
949// Move banner out of pullquote
950///////////////////////////////////////
951// const innerSponsored = document.querySelector("#slot-two");
952// const sponsoredWhitepaper = document.querySelector(".sponsored-whitepaper");
953
954// if (innerSponsored)
955//   cloneElement(
956//     '#slot-two',
957//     "BLOCKQUOTE",
958//     '',
959//     "beforebegin",
960//     false
961//   );
962// if (sponsoredWhitepaper)
963//   cloneElement(
964//     '.sponsored-whitepaper',
965//     "BLOCKQUOTE",
966//     '',
967//     "beforebegin",
968//     false
969//   );
970
971///////////////////////////////////////
972// Clone the Rankings page filters and add them inside a pop-up in mobile
973///////////////////////////////////////
974
975const rankingsMobileFilters = () => {
976  debugSep22UI();
977  // First create a new element for the modal and add a class
978  const filtersModal = document.createElement("div");
979  filtersModal.classList.add("filters-modal");
980
981  // Next add the modal to the page only in mobile
982  if (document.body.offsetWidth < 980)
983    document.body.insertAdjacentElement("beforeend", filtersModal);
984
985  // Then clone the filters inside the modal
986  cloneBanner("#modal-three", "DIV", ".filters-modal", "beforeend", true);
987
988  document
989    .querySelector(".btn-mobile-filters")
990    .addEventListener("click", function (e) {
991      e.preventDefault();
992      filtersModal.classList.add("open");
993    });
994
995  filtersModal.addEventListener("click", function (e) {
996    if (e.target.classList.contains("select-selected"))
997      e.target.nextElementSibling.classList.toggle("select-hide");
998
999    const selectItems = document.querySelectorAll(".select-items div");
1000    [...selectItems].forEach((item) => {
1001      if (item.textContent === e.target.textContent) {
1002        e.target.parentElement.previousElementSibling.value =
1003          e.target.textContent;
1004        e.target.parentElement.previousElementSibling.textContent =
1005          e.target.textContent;
1006        e.target.parentElement.classList.add("select-hide");
1007      }
1008    });
1009
1010    if (e.target.classList.contains("modal-exit"))
1011      filtersModal.classList.remove("open");
1012  });
1013};
1014if (document.querySelector(".search-and-table")) rankingsMobileFilters();
1015
1016// const premiumInsightsBanner = document.querySelector('.premium-insights-banner');
1017// if (premiumInsightsBanner) cloneBanner(premiumInsightsBanner, "DIV", '.drop-cap', 'afterend', true, 'mobile-only');
1018
1019///////////////////////////////////////
1020// Half donut
1021///////////////////////////////////////
1022const halfDonuts = document.querySelectorAll(".half-donut");
1023const createHalfDonuts = (maxValue, donuts, maxWidth) => {
1024  debugSep22UI();
1025
1026  [...donuts].forEach((donut) => {
1027    donut.style.maxWidth = `${maxWidth}px`;
1028
1029    // Bar width
1030    const percent = (Number(donut.textContent) / maxValue) * 100;
1031
1032    // Container width -- to make a responsive circle
1033    const width = donut.getBoundingClientRect().width;
1034
1035    const container = document.createElement("div");
1036    container.classList.add("container");
1037
1038    container.style.height = `${width / 2}px`;
1039
1040    donut.insertAdjacentElement("afterbegin", container);
1041
1042    // Semi circle
1043    const semiCircle = document.createElement("div");
1044    semiCircle.classList.add("semi-circle");
1045    semiCircle.style.height = `${width}px`;
1046    container.insertAdjacentElement("afterbegin", semiCircle);
1047
1048    // Semi circle cover
1049    const semiCircleCover = document.createElement("div");
1050    semiCircleCover.classList.add("semi-circle-cover");
1051    semiCircleCover.style.height = `${width - 120}px`;
1052    container.insertAdjacentElement("afterbegin", semiCircleCover);
1053
1054    // Rotate the square based on it's position
1055    const rotate = (percent - 50) * 1.8;
1056
1057    // Square
1058    const square = document.createElement("div");
1059    square.classList.add("square");
1060    square.style.rotate = `${rotate}deg`;
1061    container.insertAdjacentElement("afterbegin", square);
1062
1063    if (percent > 85) square.classList.add("over-85");
1064
1065    // Bar cover
1066    const barCover = document.createElement("div");
1067    barCover.classList.add("bar-cover");
1068    barCover.style.height = `${width + 320}px`;
1069    container.insertAdjacentElement("afterbegin", barCover);
1070  });
1071};
1072if (halfDonuts[0]) {
1073  createHalfDonuts(1000, halfDonuts, 500);
1074
1075  // If the window is resized, resize the donut by deleting and recreating it:
1076  window.addEventListener("resize", function () {
1077    const container = document.querySelector(".half-donut .container");
1078    const semiCircle = document.querySelector(".half-donut .semi-circle");
1079    const semiCircleCover = document.querySelector(
1080      ".half-donut .semi-circle-cover",
1081    );
1082    const square = document.querySelector(".half-donut .container");
1083    const barCover = document.querySelector(".half-donut .container");
1084
1085    if (container)
1086      [container, semiCircle, semiCircleCover, square, barCover].forEach((el) =>
1087        el.remove(),
1088      );
1089
1090    createHalfDonuts(1000, halfDonuts);
1091  });
1092}
1093
1094///////////////////////////////////////
1095// Rankings subcategory: Function to add a class if some text is on the page
1096///////////////////////////////////////
1097const addClassTo = (elementToAddClass, textContainer, text, className) => {
1098  debugSep22UI();
1099  const textElement = document.querySelector(textContainer);
1100  const classElement = document.querySelector(elementToAddClass);
1101  if (textElement.textContent === text) classElement.classList.add(className);
1102};
1103const categoryH1 = document.querySelector(".category-page h1");
1104if (categoryH1) {
1105  addClassTo(
1106    "body",
1107    ".category-page h1",
1108    "Most Recent Rankings in Innovation",
1109    "rankings-subcategory",
1110  );
1111  addClassTo("body", ".category-page h1", `Buyer's Guides`, "remove-sidebar");
1112  addClassTo("body", ".category-page h1", `Buyer's Guide`, "remove-sidebar");
1113  addClassTo(
1114    "body",
1115    ".category-page h1",
1116    "Most Recent Rankings in Innovation",
1117    "center-category",
1118  );
1119  addClassTo(
1120    "body",
1121    ".category-page h1",
1122    "Country Rankings",
1123    "center-category",
1124  );
1125}
1126
1127///////////////////////////////////////
1128// Disable a link: Used to disable the Rankings breadcrumb link but could be used anywhere. Make a link not clickable
1129///////////////////////////////////////
1130const disableLink = (selector, textContent, cssClass) => {
1131  debugSep22UI();
1132  const links = document.querySelectorAll(selector);
1133  [...links].forEach((link) => {
1134    if (link.textContent === textContent) {
1135      link.style.cursor = "auto";
1136      link.classList.add(cssClass);
1137      link.addEventListener("click", (e) => e.preventDefault());
1138    }
1139  });
1140};
1141disableLink(".breadcrumb a", "Rankings", "rankings-breadcrumb");
1142disableLink(
1143  ".next-previous .disabled a",
1144  `Next
1145                                edition`,
1146);
1147disableLink(
1148  ".next-previous .disabled a",
1149  `Previous
1150                                edition`,
1151);
1152
1153///////////////////////////////////////
1154//  Multiple modals on a page -- to be moved into individual modules/components
1155///////////////////////////////////////
1156
1157// Toggle a class on adjacent element on multiple elements
1158const toggleClassOnAdjacentEls = (selectors, className) =>
1159  [...selectors].forEach((link) => {
1160    alert(link.nextElementSibling);
1161    link.nextElementSibling.classList.toggle(className);
1162  });
1163
1164// On multiple elements, toggle class on parent and parent's adjacent el
1165// On single element, multipleclasses added
1166const toggleMultiParentAndNextElClasses = (selectors, className) => {
1167  const togglers = document.querySelectorAll(selectors);
1168  [...togglers].forEach((toggle) =>
1169    toggle.addEventListener("click", () => {
1170      toggle.parentElement.classList.toggle(className);
1171      toggle.parentElement.nextElementSibling.classList.toggle(className);
1172    }),
1173  );
1174};
1175const toggleMultiParentAndPrevElClasses = (selectors, className) => {
1176  const togglers = document.querySelectorAll(selectors);
1177  [...togglers].forEach((toggle) =>
1178    toggle.addEventListener("click", () => {
1179      toggle.parentElement.classList.toggle(className);
1180      toggle.parentElement.previousElementSibling.classList.toggle(className);
1181    }),
1182  );
1183};
1184// if (document.querySelectorAll('.actions .find-out-more')[0]) {
1185//   toggleMultiParentAndNextElClasses('.actions .find-out-more', 'show');
1186//   toggleMultiParentAndPrevElClasses('.included-in-these-reports .show-less', 'show');
1187// }
1188
1189///////////////////////////////////////
1190//  Show and hide multiple modals on a page using CSS classes.
1191// Add one class to control broadly. Add another for each individual modal
1192//  Used on Premium insights find out more modal
1193///////////////////////////////////////
1194const showHideMultiModals = (
1195  selectorsNodeList,
1196  classToControlDisplay,
1197  elementToAddClassTo,
1198  singleModalSelectorToAddClassTo,
1199) => {
1200  [...selectorsNodeList].forEach((el, i) =>
1201    el.addEventListener("click", (e) => {
1202      e.preventDefault();
1203      removeClassesBeginningWith(elementToAddClassTo, classToControlDisplay);
1204
1205      //if (singleModalSelectorToAddClassTo) document.querySelector(singleModalSelectorToAddClassTo).classList.toggle()
1206      elementToAddClassTo.classList.add(
1207        classToControlDisplay,
1208        `${classToControlDisplay}-${i + 1}`,
1209      );
1210    }),
1211  );
1212};
1213
1214///////////////////////////////////////
1215//  Reveal something when clicked: share with colleague on newsletters pages
1216///////////////////////////////////////
1217const shareWithColleague = document.querySelectorAll(".share-with-colleague");
1218if (shareWithColleague)
1219  [...shareWithColleague].forEach((el) =>
1220    el.addEventListener("click", () =>
1221      el.querySelector("ul").classList.toggle("reveal"),
1222    ),
1223  );
1224
1225///////////////////////////////////////
1226//  Multiple modals on a page -- to be moved into individual modules/components
1227///////////////////////////////////////
1228
1229///////////////////////////////////////
1230//  Toggle a class on adjacent HTML to show/hide the HTML -- used on Premium Insight page
1231///////////////////////////////////////
1232
1233// On single element
1234const toggleClassOnAdjacentEl = (selector, className) =>
1235  selector.nextElementSibling.classList.toggle(className);
1236const toggleClassesOnAdjacentEls = (
1237  selector,
1238  selectorClassName,
1239  nextElClassName,
1240  parentElClassName,
1241  grandParentElClassName,
1242) => {
1243  // Then add new ones
1244  selector.classList.toggle(selectorClassName);
1245  selector.nextElementSibling.classList.toggle(nextElClassName);
1246  selector.parentElement.classList.toggle(parentElClassName);
1247  selector.parentElement.parentElement.classList.toggle(grandParentElClassName);
1248};
1249
1250///////////////////////////////////////
1251//  Close a modal by removing a class
1252///////////////////////////////////////
1253const closeModal = (className1, className2) =>
1254  document.body.classList.remove(className1, className2);
1255const removeClassesOnElVar = (className1, className2, elementVariable) =>
1256  elementVariable.classList.remove(className1, className2);
1257const removeClassesOnElSelector = (className1, className2, elementSelector) =>
1258  document
1259    .querySelector(elementSelector)
1260    .classList.remove(className1, className2);
1261
1262///////////////////////////////////////
1263//  Remove classes that begin with...
1264///////////////////////////////////////
1265const removeClassesBeginningWith = (elementSelector, classNameStartsWith) =>
1266  [...elementSelector.classList].forEach((elClassName) =>
1267    elClassName.startsWith(classNameStartsWith)
1268      ? elementSelector.classList.remove(elClassName)
1269      : "",
1270  );
1271
1272///////////////////////////////////////
1273//  Create a background behind any modal
1274///////////////////////////////////////
1275const createModalBackground = (
1276  selector,
1277  bgClassName,
1278  handler,
1279  className1,
1280  className2,
1281) => {
1282  const modalBg = document.createElement("div");
1283  modalBg.classList.add(bgClassName, "modal-bg");
1284  document.querySelector(selector).insertAdjacentElement("afterend", modalBg);
1285
1286  modalBg.addEventListener("click", () => {
1287    handler(className1, className2);
1288  });
1289};
1290///////////////////////////////////////
1291//  Newsletter page modal
1292///////////////////////////////////////
1293const GDMModalTriggers = document.querySelectorAll(
1294  ".gdm-newsletter-modal-trigger",
1295);
1296
1297const GDMNewsletterModal = document.querySelector(".gdm-newsletter-modal");
1298if (GDMModalTriggers[0]) {
1299  GDMModalTriggers.forEach((trigger) => {
1300    trigger.addEventListener("click", (e) => {
1301      e.preventDefault();
1302      GDMNewsletterModal.classList.add("open", "expanded");
1303    });
1304  });
1305
1306  document
1307    .querySelector(".gdm-newsletter-modal-close")
1308    .addEventListener("click", () => {
1309      removeClassesOnElVar("open", "expanded", GDMNewsletterModal);
1310    });
1311}
1312
1313///////////////////////////////////////
1314// Add a close button to a modal
1315///////////////////////////////////////
1316const addCloseButton = (
1317  modal,
1318  buttonClass,
1319  buttonText,
1320  handler,
1321  className1,
1322  className2,
1323  modalSelectorIsVariable,
1324) => {
1325  // Guard clause: return if the close button has already been added
1326  if (modal.querySelector(`.${buttonClass}`)) return;
1327
1328  const closeButton = document.createElement("div");
1329  closeButton.classList.add(buttonClass);
1330  closeButton.textContent = buttonText;
1331
1332  closeButton.addEventListener("click", (e) => {
1333    handler(className1, className2);
1334  });
1335  modal.insertAdjacentElement("beforeend", closeButton);
1336};
1337
1338///////////////////////////////////////
1339//  Premium Insights Landing Page
1340///////////////////////////////////////
1341const PIReports = document.querySelectorAll(".pi-reports-categories .report");
1342if (PIReports[0])
1343  [...PIReports].forEach((el) => {
1344    const toggleShowAll = () => {
1345      el.classList.toggle("show-all-text");
1346      if (el.querySelector(".hidden-text"))
1347        el.querySelector(".hidden-text").classList.toggle("hidden");
1348
1349      const orangeTicksHeight = () =>
1350        `${
1351          el.querySelector(".included-in-these-reports .orange-ticks")
1352            .offsetHeight + 60
1353        }px`;
1354
1355      el.classList.contains("show-all-text")
1356        ? (el.style.minHeight = orangeTicksHeight())
1357        : (el.style.minHeight = "0");
1358    };
1359    el.querySelector(".find-out-more").addEventListener("click", toggleShowAll);
1360    el.querySelector(".close-cross").addEventListener("click", toggleShowAll);
1361    el.querySelector(".included-in-these-reports .show-less").addEventListener(
1362      "click",
1363      toggleShowAll,
1364    );
1365    el.querySelector(".actions .show-less").addEventListener(
1366      "click",
1367      toggleShowAll,
1368    );
1369  });
1370
1371///////////////////////////////////////
1372//  Remove empty strings and carriage returns
1373///////////////////////////////////////
1374const removeLineBreaksAndEmptyStrings = (text) =>
1375  text.replace(/[\n\r]+/g, "").replace(/\s{2,10}/g, " ");
1376
1377///////////////////////////////////////
1378//  Crop some text and add ellipses
1379///////////////////////////////////////
1380const cropText = (elementsSelector, charLimit) =>
1381  [...document.querySelectorAll(elementsSelector)].forEach(
1382    (title) =>
1383      (title.textContent = `${removeLineBreaksAndEmptyStrings(
1384        title.textContent,
1385      ).slice(0, charLimit)}...`),
1386  );
1387
1388///////////////////////////////////////
1389//  Crop text on recommended buyer's guides titles
1390///////////////////////////////////////
1391if (document.querySelectorAll(".gdm-buyers-guide-suggestions__card-heading"))
1392  cropText(".gdm-buyers-guide-suggestions__card-heading", 75);
1393
1394///////////////////////////////////////
1395//  Close Modal based on cancel button click
1396///////////////////////////////////////
1397const GDMForms = document.querySelectorAll("form");
1398[...GDMForms].forEach((form) => {
1399  const cancelButton = form.querySelector(".cancel-button");
1400  if (cancelButton)
1401    cancelButton.addEventListener("click", () =>
1402      cancelButton.closest(".modal").classList.remove("open"),
1403    );
1404});
1405
1406//////////////////////////////////////////////////////////
1407//////////////////////////////////////////////////////////
1408///////////////// For working on localhost and Utilities  ///////////////
1409//////////////////////////////////////////////////////////
1410//////////////////////////////////////////////////////////
1411
1412// Load the images from the live site
1413// const loadLiveImages = (environment) => {
1414//   [...document.querySelectorAll("img")].forEach((img) => {
1415//     let liveImgURL = '';
1416//     if (window.location.href.includes("localhost")) {
1417//       liveImgURL = img.src
1418//         .replace("localhost/", "")
1419//         .replace("/wp-content", ".com/wp-content");
1420//     }
1421//     if (window.location.href.includes(environment)) {
1422//       const getPosition = (string, subString, index) => string.split(subString, index).join(subString).length;
1423//       const branch = environment.slice(0, environment[getPosition(environment, '-', 2)])
1424//       alert(branch);
1425//       liveImgURL = img.src.replace(branch, "live");
1426//     }
1427//     liveImgURL !== '' && img.setAttribute("src", liveImgURL);
1428//   });
1429// };
1430// if (window.location.href.includes("localhost")) loadLiveImages();
1431// if (window.location.href.includes("pr-chris-b2b-gdm-figaro1.pantheonsite.io")) loadLiveImages('pr-chris-b2b-gdm-figaro1.pantheonsite.io');
1432
1433// Remove the OneTrust pop-up that pop-ups every single time you load the page
1434// const removeOneTrust = () => {
1435//   const oneTrustHTML = document.querySelector("#onetrust-consent-sdk");
1436
1437//   // Auto remove OneTrust:
1438//   window.addEventListener("load", function () {
1439//     setTimeout(function () {
1440//       if (oneTrustHTML) oneTrustHTML.remove();
1441//     }, 2000);
1442//   });
1443// };
1444
1445//if (window.location.href.includes("localhost")) removeOneTrust();
1446
1447// For testing
1448// window.addEventListener('scroll', function () {
1449//     window.scrollTo(0, 0);
1450//     document.body.insertAdjacentHTML("beforeend", sizeTestingSquare);
1451// });
1452
1453// window.addEventListener('scroll', function () {
1454//     const sizeTestingSquare = `< div class="size-testing-square" >
1455//     <p>Inner height = ${window.innerHeight}</p>
1456//     </div>
1457//     <div class="scroll-testing-square">
1458//     <p>ScrollY = ${Math.round(window.scrollY)}</p>
1459//     </div>
1460//     `;
1461//     document.body.insertAdjacentHTML("beforeend", sizeTestingSquare);
1462// });

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.