1class LazyLoader { 2 constructor() { 3 this.load = this.load.bind(this) 4 } 5 6 load() { 7 requestAnimationFrame(() => { 8 this.lazyImgLoad() 9 this.lazyBackgrounLoad() 10 this.lazyLinkLoad() 11 }) 12 } 13 14 lazyImgLoad() { 15 function setDimension(imgEl, width = 100, height = 100) { 16 requestAnimationFrame(() => { 17 imgEl.width = width 18 imgEl.height = height 19 }) 20 } 21 22 function applyLazyLoad(imgEl) { 23 const dataSrc = imgEl.getAttribute('data-src') 24 if (dataSrc) { 25 imgEl.addEventListener('load', () => { 26 imgEl.style.opacity = null 27 setDimension(imgEl, imgEl.naturalWidth, imgEl.naturalHeight) 28 }) 29 imgEl.src = dataSrc 30 imgEl.classList.remove('lazy') 31 imgEl.removeAttribute('data-src') 32 } else { 33 imgEl.style.opacity = null 34 if (imgEl.naturalWidth > 0 && imgEl.naturalHeight > 0) { 35 setDimension(imgEl, imgEl.naturalWidth, imgEl.naturalHeight) 36 } 37 } 38 } 39 40 const imageEls = document.querySelectorAll("img.lazy") 41 if ("IntersectionObserver" in window && !isSafari()) { 42 const observer = new IntersectionObserver((entries, observer) => { 43 entries.forEach((entry) => { 44 if (!entry.isIntersecting) return 45 46 let lazyImage = entry.target 47 if (getComputedStyle(lazyImage).display === 'none') return 48 49 applyLazyLoad(lazyImage) 50 51 if (!isSafari()) observer.unobserve(lazyImage) 52 // console.log("lazy loaded", lazyImage) 53 }) 54 }) 55 56 imageEls.forEach((imageEl) => { 57 imageEl.alt = "" 58 imageEl.style.opacity = 0 59 imageEl.style.transition = 'opacity 0.5s ease-in-out' 60 setDimension(imageEl) 61 observer.observe(imageEl) 62 }) 63 } else { 64 imageEls.forEach((imageEl) => { 65 imageEl.alt = "" 66 imageEl.style.opacity = 0 67 imageEl.style.transition = 'opacity 0.5s ease-in-out' 68 applyLazyLoad(imageEl) 69 }) 70 } 71 } 72 73 lazyBackgrounLoad() { 74 const els = document.querySelectorAll("div.lazy") 75 if ("IntersectionObserver" in window) { 76 const observer = new IntersectionObserver((entries, observer) => { 77 entries.forEach((entry) => { 78 if (!entry.isIntersecting) return 79 80 let lazyImage = entry.target 81 82 const dataSrc = lazyImage.getAttribute("data-src") 83 if (dataSrc.includes("url")) { 84 lazyImage.style.backgroundImage = dataSrc 85 } else { 86 lazyImage.style.backgroundImage = `url("${lazyImage.getAttribute("data-src")}")` 87 } 88 lazyImage.classList.remove("lazy") 89 observer.unobserve(lazyImage) 90 // console.log(lazyImage) 91 }) 92 }) 93 94 els.forEach((el) => { 95 observer.observe(el) 96 }) 97 } else { 98 els.forEach((el) => { 99 el.style.backgroundImage = el.getAttribute("data-src") 100 }) 101 } 102 } 103 104 lazyLinkLoad() { 105 const els = document.querySelectorAll("a.lazy") 106 if ("IntersectionObserver" in window) { 107 const observer = new IntersectionObserver((entries, observer) => { 108 entries.forEach((entry) => { 109 if (!entry.isIntersecting) return 110 111 let lazyA = entry.target 112 113 const innerHtml = lazyA.getAttribute("data-src") 114 lazyA.innerHTML = innerHtml 115 lazyA.classList.remove("lazy") 116 observer.unobserve(lazyA) 117 // console.log(lazyA) 118 }) 119 }) 120 121 els.forEach((el) => { 122 observer.observe(el) 123 }) 124 } else { 125 els.forEach((el) => { 126 el.style.innerHTML = el.getAttribute("data-src") 127 }) 128 } 129 } 130} 131 132class LazyFontLoader { 133 head 134 135 constructor() { 136 // Add preconnect 137 const preconnectEl = document.createElement('link') 138 preconnectEl.rel = 'preconnect' 139 preconnectEl.href = 'https://fonts.googleapis.com' 140 this.headEl.appendChild(preconnectEl) 141 } 142 143 get headEl() { 144 if (this.head) return this.head 145 this.head = document.getElementsByTagName('head')[0]; 146 return this.head 147 } 148 149 loadFont = (url) => { 150 // the 'fetch' equivalent has caching issues 151 var xhr = new XMLHttpRequest(); 152 xhr.open('GET', url, true); 153 // xhr.setRequestHeader('Access-Control-Allow-Origin', '*') 154 xhr.onreadystatechange = () => { 155 if (xhr.readyState == 4 && xhr.status == 200) { 156 let css = xhr.responseText; 157 css = css.replace(/}/g, 'font-display: swap; }'); 158 159 const style = document.createElement('style'); 160 const el = document.createTextNode(css) 161 style.appendChild(el); 162 this.headEl.appendChild(style); 163 } 164 }; 165 xhr.send(); 166 } 167}
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.