1/* 2 A JavaScript plugin for lazy-loading responsive Google Adsense ads. 3 - 4 By Osvaldas Valutis, www.osvaldas.info 5 Available for use under the MIT License 6*/ 7 8;(function (root, factory) { 9 const pluginName = 'adsenseLoader'; 10 if (typeof define === 'function' && define.amd) define([], factory(pluginName)); 11 else if (typeof exports === 'object') module.exports = factory(pluginName); 12 else root[pluginName] = factory(pluginName); 13 14}(this, function () { 15 let getAdWidth = function (ad) { 16 return parseInt(window.getComputedStyle(ad, ':before').getPropertyValue('content').slice(1, -1) || 9999); 17 }; 18 let removeAdFromList = function (list, element) { 19 return list.filter(function (entry) { 20 return entry !== element; 21 }); 22 }; 23 'use strict'; 24 25 let scriptUrl = '//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js', 26 scriptLoaded = false, 27 throttleTO = 250, 28 29 defaultOpts = 30 { 31 laziness: 1, 32 onLoad: false, 33 }, 34 35 extendObj = function (defaults, options) { 36 let prop, extended = {}; 37 for (prop in defaults) 38 if (Object.prototype.hasOwnProperty.call(defaults, prop)) 39 extended[prop] = defaults[prop]; 40 41 for (prop in options) 42 if (Object.prototype.hasOwnProperty.call(options, prop)) 43 extended[prop] = options[prop]; 44 45 return extended; 46 }, 47 48 addClass = function (el, className) { 49 if (el.classList) el.classList.add(className); 50 else el.className += ' ' + className; 51 }, 52 53 getOffset = function (el) { 54 const rect = el.getBoundingClientRect(); 55 return {top: rect.top + document.body.scrollTop, left: rect.left + document.body.scrollLeft}; 56 }, 57 58 loadScript = function (url, callback) { 59 const s = document.createElement('script'); 60 s.src = url; 61 s.async = true; 62 s.addEventListener('load', function () { 63 s.parentNode.removeChild(s); 64 if (typeof callback === 'function') 65 callback(); 66 }); 67 document.body.appendChild(s); 68 }, 69 70 throttle = function (a, b) { 71 let c, d; 72 return function () { 73 let e = this, f = arguments, g = +new Date; 74 c && g < c + a ? (clearTimeout(d), d = setTimeout(function () { 75 c = g, b.apply(e, f) 76 }, a)) : (c = g, b.apply(e, f)) 77 } 78 }, 79 80 isHidden = function(el) { 81 return (el.offsetParent === null) 82 }, 83 84 adsToLoad = [], 85 adsLoaded = [], 86 adsPending = [], 87 88 loadAd = function (ad) { 89 (adsbygoogle = window.adsbygoogle || []).push({}); 90 91 const onLoadFn = ad._adsenseLoaderData.options.onLoad; 92 if (typeof onLoadFn === 'function') { 93 ad.querySelector('iframe').addEventListener('load', function () { 94 onLoadFn(ad); 95 }); 96 } 97 }, 98 initAds = function () { 99 if (!adsToLoad.length) return true; 100 101 let winScroll = window.pageYOffset, 102 winHeight = window.innerHeight; 103 104 adsToLoad.forEach(function (ad) { 105 let offset = getOffset(ad).top, 106 laziness = ad._adsenseLoaderData.options.laziness + 1; 107 108 // if the element is too far below || too far above 109 if (offset - winScroll > winHeight * laziness || winScroll - offset - ad.offsetHeight - (winHeight * laziness) > 0) 110 return true; 111 112 if(isHidden(ad)) { 113 return true; 114 } 115 116 adsToLoad = removeAdFromList(adsToLoad, ad); 117 ad._adsenseLoaderData.width = getAdWidth(ad); 118 addClass(ad.children[0], 'adsbygoogle'); 119 adsLoaded.push(ad); 120 121 if (typeof adsbygoogle !== 'undefined') loadAd(ad); 122 else adsPending.push(ad); 123 124 if (!scriptLoaded) { 125 scriptLoaded = true; 126 loadScript(scriptUrl, function () { 127 adsPending.forEach(loadAd); 128 }); 129 } 130 }); 131 }, 132 normalizeAdElement = function (ad, options) { 133 ad._adsenseLoaderData = 134 { 135 originalHTML: ad.innerHTML, 136 options: options 137 }; 138 ad.adsenseLoader = function (method) { 139 if (method === 'destroy') {
140 adsToLoad = removeAdFromList(adsToLoad, ad); 141 adsLoaded = removeAdFromList(adsLoaded, ad); 142 adsPending = removeAdFromList(adsLoaded, ad); 143 ad.innerHTML = ad._adsenseLoaderData.originalHTML; 144 } 145 }; 146 return ad; 147 }; 148 149 150 window.addEventListener('scroll', throttle(throttleTO, initAds)); 151 152 function Plugin(elements, options) { 153 if (typeof elements === 'string') elements = document.querySelectorAll(elements); 154 else if (typeof elements.length === 'undefined') elements = [elements]; 155 156 options = extendObj(defaultOpts, options); 157 158 [].forEach.call(elements, function (entry) { 159 entry = normalizeAdElement(entry, options); 160 adsToLoad.push(entry); 161 }); 162 163 this.elements = elements; 164 165 initAds(); 166 } 167 168 Plugin.prototype = 169 { 170 destroy: function () { 171 this.elements.forEach(function (entry) { 172 entry.adsenseLoader('destroy'); 173 }); 174 } 175 }; 176 177 window.adsenseLoaderConfig = function (options) { 178 if (typeof options.scriptUrl !== 'undefined') 179 scriptUrl = options.scriptUrl; 180 181 if (typeof options.throttle !== 'undefined') 182 throttleTO = options.throttle; 183 }; 184 185 return Plugin; 186}));
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.