1/** 2 * File main.js. 3 * 4 * Handles toggling the navigation menu for small screens and enables TAB key 5 * navigation support for dropdown menus. 6 * 7 * Also handles all the search forms and block animations. 8 */ 9 10function getQueryParams() { 11 let params = {}; 12 let queryString = window.location.search.substring(1); 13 let pairs = queryString.split("&"); 14 15 for (let i = 0; i < pairs.length; i++) { 16 let pair = pairs[i].split("="); 17 let key = decodeURIComponent(pair[0].replace(/\[\]$/, "")); // Remove [] from the name 18 let value = decodeURIComponent(pair[1] || ""); 19 20 if (!params[key]) { 21 params[key] = []; 22 } 23 params[key].push(value); 24 } 25 return params; 26} 27 28 // Function to expand an element 29 function expandElement(element) { 30 element.style.height = element.scrollHeight + 'px'; // Set height to scrollHeight 31 element.classList.add('active'); 32 element.addEventListener('transitionend', function handler() { 33 element.style.height = 'auto'; // Reset to auto after transition 34 element.removeEventListener('transitionend', handler); 35 }); 36 } 37 38 // Function to collapse an element 39 function collapseElement(element) { 40 element.style.height = element.scrollHeight + 'px'; // Set height to current scrollHeight 41 requestAnimationFrame(() => { 42 element.style.height = '0'; // Transition to 0 43 }); 44 element.classList.remove('active'); 45 } 46 47 48 49 50 51 52( function() { 53 // SOCIAL SHARING JS 54 document.addEventListener("DOMContentLoaded", function () { 55 const shareButtons = document.querySelectorAll(".social-sharing-buttons a"); 56 const copyLinkButton = document.querySelector(".copy-link-button"); 57 const copyToast = document.querySelector("#copy-toast"); 58 59 shareButtons.forEach((button) => { 60 button.addEventListener("click", function (event) { 61 if (!this.classList.contains("copy-link-button")) { 62 event.preventDefault(); 63 const width = 600, 64 height = 400; 65 const left = screen.width / 2 - width / 2; 66 const top = screen.height / 2 - height / 2; 67 const url = this.href; 68 window.open( 69 url, 70 "Share", 71 `width=${width},height=${height},top=${top},left=${left}` 72 ); 73 } 74 }); 75 }); 76 77 if (copyLinkButton) { 78 copyLinkButton.addEventListener("click", function (event) { 79 event.preventDefault(); 80 const url = this.getAttribute("data-url"); 81 82 navigator.clipboard 83 .writeText(url) 84 .then(() => { 85 //alert('Link copied to clipboard!'); 86 copyToast.classList.add("active"); 87 88 setTimeout(() => { 89 copyToast.classList.remove("active"); 90 }, 1500); 91 }) 92 .catch((err) => { 93 console.error("Could not copy text: ", err); 94 }); 95 }); 96 } 97 }); 98})(); 99 100 101 102 103 104 105 106/** Testimonial Carousel */ 107function getTallestElementInRem(parentElement) { 108 const children = parentElement.children; 109 let maxHeight = 0; 110 111 // Loop through all child elements to find the tallest one 112 for (let i = 0; i < children.length; i++) { 113 const childHeight = children[i].offsetHeight; 114 if (childHeight > maxHeight) { 115 maxHeight = childHeight; 116 } 117 } 118 119 // Get the root font-size to convert pixels to rem 120 const rootFontSize = parseFloat( 121 getComputedStyle(document.documentElement).fontSize 122 ); 123 124 // Convert max height to rem (1rem = rootFontSize pixels) 125 const maxHeightInRem = maxHeight / rootFontSize; 126 127 parentElement.style = `--_carousel-min-height: ${maxHeightInRem}rem`; 128 129 return maxHeightInRem.toFixed(2); // Returning the value in rem, rounded to 2 decimal places 130} 131 132/** 133 * Testimonial Carousel Execution 134 */ 135(function () { 136 document.addEventListener("DOMContentLoaded", function () { 137 138 const testimonialBlock = document.querySelectorAll(".testimonial-carousel"); 139 140 if(!testimonialBlock) return; 141 142 testimonialBlock.forEach( block => { 143 144 const quotes = block.querySelectorAll(".carousel__body"); 145 const people = block.querySelectorAll(".carousel__person"); 146 147 const quotesWrap = block.querySelector(".carousel__testimonials"); 148 const peopleWrap = block.querySelector(".carousel__people"); 149 150 const nextButton = block.querySelector(".carousel__button--next"); 151 const prevButton = block.querySelector(".carousel__button--prev"); 152 153 const currentCount = block.querySelector(".count.current"); 154 155 let currentIndex = 0; 156 const totalSlides = quotes.length; 157 158 // Set the default heights. 159 getTallestElementInRem(quotesWrap); 160 getTallestElementInRem(peopleWrap); 161 162 function toggleActiveTestimonial( items = [] ) {
163 items.forEach((item, i) => { 164 item.classList.remove("active"); 165 if (i === currentIndex) { 166 item.classList.add("active"); 167 } 168 }); 169 } 170 171 function showTestimonial(index) { 172 toggleActiveTestimonial(quotes); 173 toggleActiveTestimonial(people); 174 currentCount.textContent = currentIndex+1; 175 } 176 177 function nextTestimonial() { 178 currentIndex = (currentIndex + 1) % totalSlides; 179 block.dataset.currentIndex = currentIndex; 180 181 showTestimonial(currentIndex); 182 } 183 184 function prevTestimonial() { 185 currentIndex =(currentIndex - 1 + totalSlides) % totalSlides; 186 block.dataset.currentIndex = currentIndex; 187 188 showTestimonial(currentIndex); 189 } 190 191 nextButton.addEventListener("click", nextTestimonial); 192 prevButton.addEventListener("click", prevTestimonial); 193 }); 194 }); 195})(); 196 197 198 199/** 200 * Full Feature Block Lightbox 201 */ 202(function () { 203 document.addEventListener("DOMContentLoaded", function () { 204 const fullFeatureBlocks = document.querySelectorAll( 205 ".block__full-feature.full-cover" 206 ); 207 208 if (!fullFeatureBlocks) return; 209 210 fullFeatureBlocks.forEach((block) => { 211 const playButton = block.querySelector(".feature-play-button"); 212 const lightbox = block.querySelector(".lightbox-wrap"); 213 const close = block.querySelector(".lightbox-close"); 214 215 if (playButton) { 216 playButton.addEventListener("click", function () { 217 lightbox.classList.add("open"); 218 }); 219 } 220 221 if (close) { 222 close.addEventListener("click", function () { 223 lightbox.classList.remove("open"); 224 }); 225 } 226 }); 227 228 // Lazy load the lozads 229 if (typeof window.lozad === "function") { 230 const observer = lozad(); 231 observer.observe(); 232 } 233 }); 234})(); 235 236 237// SWUP 238/* 239const swup = new Swup({ 240 containers: ["#primary"], 241 plugins: [ 242 new SwupHeadPlugin(), 243 new SwupPreloadPlugin(), 244 new SwupFadeTheme(), 245 //new SwupScrollPlugin(), 246 ], 247}); 248*/ 249 250 251/** 252 * Course Card Link Goodness 253 */ 254(function () { 255 document.querySelectorAll(".card.card__study").forEach((card) => { 256 const link = card.querySelector("a[href]"); 257 if (!link) return; 258 259 card.style.cursor = "pointer"; 260 261 card.addEventListener("click", (e) => { 262 // Prevent navigating if a real link or button inside the card is clicked 263 const isInteractive = e.target.closest("a, button"); 264 if (isInteractive) return; 265 266 window.location = link.href; 267 }); 268 }); 269})(); 270 271 272(function () { 273 document.querySelectorAll(".testimonial__track").forEach((track) => { 274 let isDragging = false; 275 let startX = 0; 276 let scrollStart = 0; 277 278 const startDrag = (e) => { 279 isDragging = true; 280 startX = e.clientX; 281 scrollStart = track.scrollLeft; 282 track.setPointerCapture(e.pointerId); 283 track.classList.add("dragging"); 284 }; 285 286 const onDrag = (e) => { 287 if (!isDragging) return; 288 const dx = e.clientX - startX; 289 track.scrollLeft = scrollStart - dx * 3.5; // Tweak multiplier 290 }; 291 292 const stopDrag = (e) => { 293 isDragging = false; 294 track.releasePointerCapture(e.pointerId); 295 track.classList.remove("dragging"); 296 }; 297 298 track.addEventListener("pointerdown", startDrag); 299 track.addEventListener("pointermove", onDrag); 300 track.addEventListener("pointerup", stopDrag); 301 track.addEventListener("pointercancel", stopDrag); 302 }); 303})(); 304 305
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.