1(function (document) { 2 /** 3 * A storage interface that uses sessionStorage when available and falls back to an in-memory object. 4 */ 5 class StorageAdapter { 6 constructor(namespace) { 7 this._namespace = namespace || 'app'; 8 this._useSessionStorage = this._isSessionStorageAvailable(); 9 this._memoryCache = {}; 10 } 11 12 /** 13 * Tests if sessionStorage is available and functional. 14 * @returns {boolean} True if sessionStorage is available. 15 */ 16 _isSessionStorageAvailable() { 17 try { 18 var testKey = '__storage_test__'; 19 sessionStorage.setItem(testKey, testKey); 20 sessionStorage.removeItem(testKey); 21 return true; 22 } catch (e) { 23 return false; 24 } 25 } 26 27 /** 28 * Gets the full key with namespace prefix. 29 * @param {string} key - The key to namespace. 30 * @returns {string} The namespaced key. 31 */ 32 _getNamespacedKey(key) { 33 return this._namespace + ':' + key; 34 } 35 36 /** 37 * Gets a value from storage. 38 * @param {string} key - The key to retrieve. 39 * @returns {*} The stored value, or null if not found. 40 */ 41 getItem(key) { 42 var namespacedKey = this._getNamespacedKey(key); 43 44 if (this._useSessionStorage) { 45 try { 46 var value = sessionStorage.getItem(namespacedKey); 47 return value ? JSON.parse(value) : null; 48 } catch (e) { 49 // Fall back to memory cache if sessionStorage fails 50 return this._memoryCache[namespacedKey] || null; 51 } 52 } 53 54 return this._memoryCache[namespacedKey] || null; 55 } 56 57 /** 58 * Sets a value in storage. 59 * @param {string} key - The key to set. 60 * @param {*} value - The value to store. 61 */ 62 setItem(key, value) { 63 var namespacedKey = this._getNamespacedKey(key); 64 65 if (this._useSessionStorage) { 66 try { 67 sessionStorage.setItem(namespacedKey, JSON.stringify(value)); 68 return; 69 } catch (e) { 70 // Fall back to memory cache if sessionStorage fails 71 this._memoryCache[namespacedKey] = value; 72 } 73 } else { 74 this._memoryCache[namespacedKey] = value; 75 } 76 } 77 78 /** 79 * Removes a value from storage. 80 * @param {string} key - The key to remove. 81 */ 82 removeItem(key) { 83 var namespacedKey = this._getNamespacedKey(key); 84 85 if (this._useSessionStorage) { 86 try { 87 sessionStorage.removeItem(namespacedKey); 88 } catch (e) { 89 // Continue to remove from memory cache 90 } 91 } 92 93 delete this._memoryCache[namespacedKey]; 94 } 95 96 /** 97 * Clears all items in the namespace. 98 */ 99 clear() { 100 if (this._useSessionStorage) { 101 try { 102 var keysToRemove = []; 103 for (var i = 0; i < sessionStorage.length; i++) { 104 var key = sessionStorage.key(i); 105 if (key && key.indexOf(this._namespace + ':') === 0) { 106 keysToRemove.push(key); 107 } 108 } 109 keysToRemove.forEach(function (key) { 110 sessionStorage.removeItem(key); 111 }); 112 } catch (e) { 113 // Continue to clear memory cache 114 } 115 } 116 117 // Clear memory cache 118 var prefix = this._namespace + ':'; 119 Object.keys(this._memoryCache).forEach(function (key) { 120 if (key.indexOf(prefix) === 0) { 121 delete this._memoryCache[key]; 122 } 123 }); 124 } 125 126 /** 127 * Checks if a key exists in storage. 128 * @param {string} key - The key to check. 129 * @returns {boolean} True if the key exists. 130 */ 131 hasItem(key) { 132 return this.getItem(key) !== null; 133 } 134 } 135 136 var countAllImpressions = false; 137 var cache = new StorageAdapter('mni-partners-viewed'); 138 var pendingEvents = []; // Queue for events before gza loads 139 140 (function () { 141 var l = getScriptTagData(); 142 var url = '//' + l.domain + '/api/widget/analytics'; 143 getData(url, function (data) { 144 if ((data || {}).Enabled) { 145 countAllImpressions = data.CountAllImpressions; 146 (function (b, d, a, c) { b.getElementById(d) || (c = b.getElementsByTagName(a)[0], a = b.createElement(a), a.type = "text/javascript", a.async = !0, a.src = '//' + l.domain + "/GZContent/analytics/gza.js", c.parentNode.insertBefore(a, c)) })(document, "mni-analytics-script", "script"); 147 } 148 }); 149 })(); 150 151 var queueVarName = '_mnipartq'; 152 153 function getPartnerKey(props) { 154 return props.tenant + '-' + props.id + '-' + props.location; 155 } 156 function hasKey(props) { 157 // if we are not counting all impressions, 158 return !countAllImpressions 159 // only check for the key if this is a view action, as clicks should always be counted 160 && props.action === 'view' 161 // check the session storage/memory cache for the key to determine if this impression has already been counted 162 && cache.hasItem(getPartnerKey(props)); 163 } 164 function setKey(props) { 165 // if we are not counting all impressions 166 if (!countAllImpressions 167 // and this is a view action, 168 && props.action === 'view') { 169 // set the key in session storage / memory cache so that subsequent impressions with the same tenant, partner, and location will not be counted 170 cache.setItem(getPartnerKey(props), true); 171 } 172 } 173 174 function getScriptTagData() { 175 var scripts = document.getElementsByTagName('script'); 176 177 for (var i = 0; i < scripts.length; i++) { 178 var script = scripts[i], 179 match = script.src.match(/^((https?:)?\/\/([^/]+))\/.+\/publicwidgets\/partners\.(min\.)?js/i); 180 181 if (match) { 182 return { 183 protocol: match[2] || window.location.protocol, 184 origin: match[1] || window.location.origin, 185 domain: match[3] || window.location.host 186 }; 187 } 188 } 189 return { 190 protocol: window.location.protocol, 191 origin: window.location.origin, 192 domain: window.location.host 193 }; 194 } 195 function parseUrl(param) { 196 return (!!param.push) ? param.join(',') : param; 197 } 198 function getUrl(params, valid) { 199 var l = getScriptTagData();
200 var v = valid ? valid.reduce(function (o, k) { o[k] = true; return o; }, {}) : null; 201 var args = Object.keys(params) 202 .filter(function (k) { return !v || !!v[k] }) 203 .map(function (k) { return k + '=' + parseUrl(params[k]) }); 204 205 return '//' + l.domain + '/api/widget/partners' + (args.length ? "?" + args.join('&') : ""); 206 } 207 function createXHR() { 208 if (window.XMLHttpRequest) 209 try { return new XMLHttpRequest(); } catch (e) { } 210 211 if (window.ActiveXObject) { 212 try { return new ActiveXObject("MSXML2.XMLHTTP"); } catch (e) { } 213 try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { } 214 } 215 } 216 function getData(url, callback) { 217 var xhr = createXHR(); 218 xhr.open('GET', url, true); 219 //xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 220 xhr.setRequestHeader('Accept', 'application/json, text/javascript, */*'); 221 xhr.onreadystatechange = function () { 222 if (this.readyState == 4 && this.status == 200) 223 callback(JSON.parse(this.responseText)); 224 }; 225 xhr.send(); 226 } 227 228 function send(props) { 229 var analytics = (window.gza || function () { })(); 230 pendingEvents.push(props); 231 if (analytics) { 232 pendingEvents.forEach(function (p) { 233 if (!hasKey(p)) { 234 analytics.track('Partner', p); 235 setKey(p); 236 } 237 }); 238 pendingEvents = []; 239 } 240 } 241 var widgets = window[queueVarName].reduce(function (o, k) { 242 var params = k[0].split('.'); 243 var id = params[0]; 244 var arg = params[1]; 245 if (!o[id]) o[id] = {}; 246 if (!o[id].loaded) o[id][arg] = k[1]; 247 return o; 248 }, {}); 249 250 Object.keys(widgets).forEach(function (k) { Init(k, widgets[k]); }); 251 252 var render = function (id, params, items, format) { 253 var width = (items[0] || {}).Width; 254 var height = (items[0] || {}).Height; 255 return '<div class="mni-partners-widget transition-' + (params['animation'] ? "fade" : "flash") + '">' + 256 //'<div class="edge"></div>' + 257 '<div class="mni-partners-container">' + 258 '<ul class="partners">' + 259 items.reduce(function (o, k) { return o + format(k) }, '') + 260 '</ul>' + 261 '</div>' + 262 '</div>' + 263 '<style> #' + id + ' .mni-partners-widget { text-align: center; } #' + id + ' .mni-partners-container { ' + (width ? ('max-width:' + width + 'px;width:100%;') : '') + (height ? ('height:' + height + 'px;') : '') + ' display: inline-block; } #' + id + ' .mni-partners-widget .partners { margin: 0px; padding: 0px; position: relative; } #' + id + ' .mni-partners-widget .partner { position: absolute; } #' + id + ' .mni-partners-widget.transition-fade .partner { -webkit-transition: opacity 1s ease; -moz-transition: opacity 1s ease; -ms-transition: opacity 1s ease; -o-transition: opacity 1s ease; transition: opacity 1s ease; opacity: 0; height: 0; overflow: hidden; } #' + id + ' .mni-partners-widget.transition-fade .partner.mn-active { opacity: 1; height: auto; } #' + id + ' .mni-partners-widget.transition-flash .partner { display:none; } #' + id + ' .mni-partners-widget.transition-flash .partner.mn-active { display:block; }</style>'; 264 }; 265 function Init(id, params) { 266 var format = function (item) { 267 return '<li class="partner" ' + 268 'data-partner-id="' + (item.AdvertisementId || 0) + '" ' + 269 'data-partner-slug="' + (item.AdvertisementSlug || 0) + '" ' + 270 'data-location-id="' + (item.AdvertisementPlacementId || 0) + '" ' + 271 'data-location-slug="' + (item.LocationSlug || 0) + '" ' + 272 'data-tenant-id="' + (item.TenantKey || 0) + '">' + 273 '<a href="' + item.URL + '" target="' + item.Target + '" >' + 274 '<image src="' + item.Image + '" alt="' + item.ImageShortDescription + '"/>' + 275 '</a>' + 276 '</li>'; 277 } 278 var id = params['create']; 279 getData(getUrl(params, ['type', 'max', 'v', 'pageId', 'position', 'categoryItemId', 'parentCategoryId']), function (items) { 280 document.getElementById(id).innerHTML = render(id, params, items, format); 281 282 var partners = document.querySelectorAll('#' + id + ' .partner'); 283 if (partners.length) { 284 for (const partner of partners) { 285 partner.addEventListener('click', function () { 286 send({ 287 action: 'click', 288 id: this.dataset.partnerId, 289 idSlug: this.dataset.partnerSlug, 290 location: this.dataset.locationId, 291 locationSlug: this.dataset.locationSlug, 292 tenant: this.dataset.tenantId 293 }); 294 }); 295 } 296 297 var all = partners.length; 298 var current = all - 2; 299 var timeout = null;
300 var delay = params['delay'] || 5; 301 function changeImg(b) { 302 var currentPartner = partners[(all - ((Math.abs(b ? --current : ++current) % all) + 1))]; 303 var triggerAnalytics = !currentPartner.classList.contains('mn-active'); 304 partners.forEach(function (p) { p.classList.remove('mn-active'); }); 305 currentPartner.classList.add('mn-active'); 306 307 if (triggerAnalytics) { 308 send({ 309 action: 'view', 310 id: currentPartner.dataset.partnerId, 311 idSlug: currentPartner.dataset.partnerSlug, 312 location: currentPartner.dataset.locationId, 313 locationSlug: currentPartner.dataset.locationSlug, 314 tenant: currentPartner.dataset.tenantId 315 }); 316 } 317 } 318 function dChangeImg(b) { 319 if (timeout) clearInterval(timeout); 320 timeout = setInterval(changeImg, (delay * 1000)); 321 changeImg(b); 322 } 323 dChangeImg(); 324 } 325 }); 326 } 327})(window.document)
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.