1/** @format */ 2 3document.addEventListener("DOMContentLoaded", () => { 4 console.log("main.js DOMContentLoaded - Lazy image fade-in script initialized"); 5 // Start script here 6 setupYouTube(); 7 8 function addAiIcons() { 9 document.querySelectorAll(".header-menu li.ai > a").forEach((link) => { 10 // skip if already added 11 if (link.querySelector("img.ai-img")) return; 12 13 const img = new Image(); 14 img.src = "/wp-content/themes/paperstreet/assets/images/ps-ai-new.svg"; 15 img.width = 15; 16 img.height = 15; 17 img.alt = "AI"; 18 img.className = "ai-img"; 19 // optional: improve rendering hints 20 img.decoding = "async"; 21 img.loading = "lazy"; 22 link.appendChild(img); 23 }); 24 } 25 26 // run when DOM is ready 27 if (document.readyState === "loading") { 28 document.addEventListener("DOMContentLoaded", addAiIcons); 29 } else { 30 addAiIcons(); 31 } 32 33 // Remove empty <p> tags inside elements with class 'tlct-shortdes' on page load 34 // See "Our Story" timeline page 35 var shortdesElements = document.querySelectorAll(".tlct-shortdes"); 36 if (shortdesElements.length > 0) { 37 shortdesElements.forEach(function (parent) { 38 parent.querySelectorAll("p").forEach(function (p) { 39 if (p.textContent.trim() === "" && p.innerHTML.trim() === "") { 40 p.remove(); 41 } 42 }); 43 }); 44 } 45 46 console.log("main.js loaded. Referrer = " + document.referrer); 47 48 // Function to get query parameters as an object 49 function getQueryParams() { 50 var params = {}; 51 var queryString = window.location.search.substring(1); 52 if (queryString) { 53 var pairs = queryString.split("&"); 54 for (var i = 0; i < pairs.length; i++) { 55 var pair = pairs[i].split("="); 56 params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || ""); 57 } 58 } 59 return params; 60 } 61 62 // Function to store referrer and current URL on first visit 63 function storeOnFirstVisit() { 64 // Check if it's the user's first visit 65 if (!localStorage.getItem("firstVisit")) { 66 // Store the referrer 67 var referrer = document.referrer || "Direct Visit"; 68 localStorage.setItem("referrer", referrer); 69 70 // Store the full current URL (including parameters) 71 var currentUrl = window.location.href; 72 localStorage.setItem("currentUrl", currentUrl); 73 74 // Store query parameters (optional, you can skip this if storing full URL) 75 var queryParams = getQueryParams(); 76 if (Object.keys(queryParams).length > 0) { 77 localStorage.setItem("storedParams", JSON.stringify(queryParams)); 78 } 79 80 // Mark that the first visit has occurred 81 localStorage.setItem("firstVisit", "true"); 82 } 83 } 84 85 // Call function to store data on first visit 86 storeOnFirstVisit(); 87 88 // Retrieve the referrer, current URL, and stored query parameters 89 var referrerInput = document.getElementById("referrerInput"); 90 var storedReferrer = localStorage.getItem("referrer") || "Direct Visit"; 91 var storedCurrentUrl = localStorage.getItem("currentUrl") || window.location.href; 92 var storedParams = JSON.parse(localStorage.getItem("storedParams")) || {}; 93 94 // Combine referrer, current URL, and query parameters if needed 95 if (referrerInput) { 96 var combinedInfo = "Referrer: " + storedReferrer + " | Full URL: " + storedCurrentUrl; 97 98 // Optionally, append stored query parameters (if separate handling of params is needed) 99 if (Object.keys(storedParams).length > 0) { 100 combinedInfo += " | Query Params: " + JSON.stringify(storedParams); 101 } 102 103 // Set the combined info to the input value 104 referrerInput.value = combinedInfo; 105 } 106 107 // Check header scroll on load 108 scrollHeaderClass(); 109 110 // GLightbox options and settings here (https://biati-digital.github.io/glightbox/) 111 if (typeof GLightbox !== "undefined") { 112 const lightbox = GLightbox(); 113 } 114 115 // add class to header when scrolling 116 window.addEventListener("scroll", scrollHeaderClass); 117 118 function scrollHeaderClass() { 119 const header = document.querySelector(".header"); 120 if (window.pageYOffset >= 100) { 121 header.classList.add("is-fixed"); 122 } else { 123 header.classList.remove("is-fixed"); 124 } 125 } 126 127 // Set header top and main margin-top based on AI banner height (only on home page) 128 function adjustLayoutForAiBanner() { 129 if (document.body.classList.contains("home") && window.innerWidth >= 1025) { 130 const aiBanner = document.getElementById("ai-banner"); 131 const header = document.querySelector(".header"); 132 const main = document.querySelector("main"); 133
134 if (aiBanner && header && main) { 135 const bannerHeight = aiBanner.offsetHeight; 136 if (bannerHeight > 0) { 137 header.style.top = bannerHeight + "px"; 138 main.style.marginTop = bannerHeight + "px"; 139 } 140 } 141 } else { 142 //remove header style attribute 143 document.querySelector(".header").removeAttribute("style"); 144 document.querySelector("main").removeAttribute("style"); 145 } 146 } 147 148 // Run on page load 149 // adjustLayoutForAiBanner(); 150 151 // Re-check on window resize in case banner height changes 152 // window.addEventListener("resize", adjustLayoutForAiBanner); 153 154 // End script here 155 156 // Lazy load images 157 let lazyImages = [].slice.call(document.querySelectorAll("img.lazy")); 158 console.log("Lazy images found:", lazyImages.length, lazyImages); 159 160 if ("IntersectionObserver" in window) { 161 let lazyImageObserver = new IntersectionObserver(function (entries, observer) { 162 entries.forEach(function (entry) { 163 if (entry.isIntersecting) { 164 let lazyImage = entry.target; 165 console.log( 166 "LazyImage entering viewport:", 167 lazyImage.dataset.src || lazyImage.src, 168 lazyImage 169 ); 170 171 // Check if image is inside a picture element 172 let pictureElement = lazyImage.closest("picture"); 173 174 if (pictureElement) { 175 // Find all source tags within the picture element 176 let sourceTags = pictureElement.querySelectorAll("source[data-srcset]"); 177 sourceTags.forEach(function (sourceTag) { 178 if (sourceTag.dataset.srcset) { 179 sourceTag.srcset = sourceTag.dataset.srcset; 180 console.log("LazyImage picture source applied:", sourceTag.srcset); 181 } 182 }); 183 } 184 185 // Trigger fade-in after image loads 186 lazyImage.addEventListener("load", function () { 187 console.log("LazyImage loaded (event), triggering fade-in:", lazyImage.src); 188 // Use requestAnimationFrame to ensure browser has processed the load 189 requestAnimationFrame(function () { 190 lazyImage.classList.add("lazy-loaded"); 191 }); 192 }); 193 194 // Apply the src to the image 195 console.log("LazyImage setting src:", lazyImage.dataset.src); 196 lazyImage.src = lazyImage.dataset.src; 197 198 // Fallback for cached images (already loaded) 199 if (lazyImage.complete && lazyImage.naturalHeight !== 0) { 200 console.log("LazyImage already cached, triggering fade-in immediately:", lazyImage.src); 201 // Use requestAnimationFrame for cached images too 202 requestAnimationFrame(function () { 203 lazyImage.classList.add("lazy-loaded"); 204 }); 205 } 206 207 lazyImageObserver.unobserve(lazyImage); 208 } 209 }); 210 }); 211 212 lazyImages.forEach(function (lazyImage) { 213 lazyImageObserver.observe(lazyImage); 214 }); 215 } 216 217 // Lazy load background images 218 let lazyBgImages = [].slice.call(document.querySelectorAll(".lazy-bg")); 219 console.log("Lazy background images found:", lazyBgImages.length, lazyBgImages); 220 221 if ("IntersectionObserver" in window) { 222 let lazyBgImageObserver = new IntersectionObserver(function (entries, observer) { 223 entries.forEach(function (entry) { 224 if (entry.isIntersecting) { 225 let lazyBgImage = entry.target; 226 console.log("LazyBgImage entering viewport:", lazyBgImage.dataset.bg, lazyBgImage); 227 228 // Create a temporary image to detect when background loads 229 let tempImg = new Image(); 230 tempImg.onload = function () { 231 console.log("LazyBgImage loaded, triggering fade-in:", lazyBgImage.dataset.bg); 232 // Use requestAnimationFrame to ensure browser has processed the load 233 requestAnimationFrame(function () { 234 lazyBgImage.classList.add("lazy-loaded"); 235 }); 236 }; 237 tempImg.src = lazyBgImage.dataset.bg; 238 239 lazyBgImage.style.backgroundImage = "url(" + lazyBgImage.dataset.bg + ")"; 240 lazyBgImageObserver.unobserve(lazyBgImage); 241 } 242 }); 243 }); 244 245 lazyBgImages.forEach(function (lazyBgImage) { 246 lazyBgImageObserver.observe(lazyBgImage); 247 }); 248 } 249 250 // Video inline play 251 const videoContainers = document.querySelectorAll("[data-video]"); 252 253 videoContainers.forEach((container) => { 254 container.addEventListener("click", function () { 255 const videoUrl = this.getAttribute("data-video"); 256 const videoId = videoUrl.split("v=")[1]; 257 const embedUrl = `https://www.youtube.com/embed/${videoId}?autoplay=1&rel=0`; 258 259 this.innerHTML = `<iframe width="560" height="315" src="${embedUrl}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`; 260 this.classList.add("is-active"); 261 }); 262 }); 263}); 264 265function setupYouTube() { 266 // Prepare YouTube video placeholders that turn into iframe on click 267 var players = document.getElementsByClassName("youtube-player"); 268 if (players.length === 0) { 269 return; 270 } 271 272 for (var n = 0; n < players.length; n++) { 273 var player = players[n]; 274 var div = document.createElement("div"); 275 div.setAttribute("data-id", player.dataset.id); 276 div.setAttribute("data-list", player.dataset.list); 277 div.innerHTML = 278 '<img src="https://img.youtube.com/vi/' + player.dataset.id + '/hqdefault.jpg" alt="">'; 279 280 // Add attributes and classes to the div to make it interactive
281 div.classList.add("youtube-player-inner"); 282 div.setAttribute("tabindex", "0"); 283 div.setAttribute("aria-label", "Play video"); 284 div.addEventListener("click", getYouTubeFrame); 285 div.addEventListener("keypress", getYouTubeFrame); 286 287 // Add the div to this player 288 player.appendChild(div); 289 } 290} 291 292function getYouTubeFrame() { 293 var iframe = document.createElement("iframe"); 294 var embed = "https://www.youtube.com/embed/ID?autoplay=1&rel=0"; 295 296 iframe.setAttribute("src", embed.replace("ID", this.dataset.id)); 297 iframe.setAttribute("frameborder", "0"); 298 iframe.setAttribute("allow", "autoplay;"); 299 iframe.setAttribute("allowfullscreen", "1"); 300 301 this.parentNode.replaceChild(iframe, this); 302}
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.