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.