1// Chartbeat â script loader and event handlers. 2// Page config (_sf_async_config) is set server-side in chartbeat.php before this script loads. 3window.chartbeat_loaded = false; 4(function () { 5 function loadChartbeat(evt = null) { 6 if (!window.chartbeat_loaded) { 7 console.debug('Loading Chartbeat scripts...', evt); 8 var n = document.getElementsByTagName('script')[0]; 9 //var _cbq = window._cbq = (window._cbq || []); 10 var isVideo = (window._sf_async_config || {}).type === 'video'; 11 if (isVideo) { 12 var v = document.createElement('script'); 13 v.async = true; 14 v.src = '//static.chartbeat.com/js/chartbeat_video.js'; 15 // cbvRegisterFlowplayer polls until Flowplayer has created fp-engine (async init). 16 v.onload = function () { 17 var attempts = 0; 18 var poll = setInterval(function () { 19 var videoEl = document.querySelector('.video-container.flowplayer video.fp-engine'); 20 if (videoEl) { 21 clearInterval(poll); 22 window._cbv.push(videoEl); 23 } else if (++attempts >= 40) { 24 clearInterval(poll); 25 } 26 }, 250); 27 }; 28 n.parentNode.insertBefore(v, n); 29 } else { 30 var e = document.createElement('script'); 31 e.async = true; 32 e.src = '//static.chartbeat.com/js/chartbeat.js'; 33 n.parentNode.insertBefore(e, n); 34 } 35 // Load MAB 36 (function () { 37 var n = document.getElementsByTagName('script')[0]; 38 var s = document.createElement('script'); 39 s.async = true; 40 s.src = '//static.chartbeat.com/js/chartbeat_mab.js'; 41 n.parentNode.insertBefore(s, n); 42 })(); 43 // Load subscriptions.js for conversion tracking 44 (function (w, d, s, c, u) { 45 var qf = function (e, a) { (w[c].q = w[c].q || []).push([e, a]); }; 46 w[c] = w[c] || qf; 47 var st = d.createElement(s); 48 var fs = d.getElementsByTagName(s)[0]; 49 st.async = 1; 50 st.src = u; 51 fs.parentNode.insertBefore(st, fs); 52 })(window, document, 'script', 'chartbeat', 'https://static.chartbeat.com/js/subscriptions.js'); 53 window.chartbeat_loaded = true; 54 } 55 } 56 document.addEventListener('chartbeat:setup', loadChartbeat); 57 document.dispatchEvent(new CustomEvent('chartbeat:loaded', { detail: { _cbq: window._cbq } })); 58})(); 59 60// --------------------------------------------------------------------------- 61// Account type â based on auth_user_data set by auth.js 62// anon â not logged in | lgdin â logged in, no subscription | paid â subscribed 63// --------------------------------------------------------------------------- 64(function () { 65 function setCbAcct(evt = null) { 66 console.debug('Setting Chartbeat account type based on user authentication/subscription status...', evt); 67 if (typeof is_logged_in == 'function' && is_logged_in()) { 68 if (typeof is_internaz_subscribed == 'function' && is_internaz_subscribed()) { 69 window._cbq.push(['_acct', 'paid']); 70 console.debug('Chartbeat account type set to "paid" (subscribed user)'); 71 } else { 72 window._cbq.push(['_acct', 'lgdin']); 73 console.debug('Chartbeat account type set to "lgdin" (logged-in user, not subscribed)'); 74 } 75 } else { 76 window._cbq.push(['_acct', 'anon']); 77 console.debug('Chartbeat account type set to "anon" (not logged in)'); 78 } 79 document.dispatchEvent(new CustomEvent('chartbeat:setup', { detail: { _cbq: window._cbq } })); 80 } 81 // auth.js may not have run yet â wait for DOMContentLoaded 82 /*if (document.readyState === 'loading') { 83 document.addEventListener('DOMContentLoaded', setCbAcct); 84 } else { 85 setCbAcct(); 86 }*/ 87 document.addEventListener('auth:loaded', setCbAcct); 88})(); 89 90function track_chartbeat_conversion(event_name, options = null) { 91 console.log('track_chartbeat_conversion', event_name, options); 92 if (typeof chartbeat == 'function') { 93 if (options && Object.keys(options).length) { 94 chartbeat(event_name, options); 95 } else { 96 chartbeat(event_name); 97 } 98 } 99} 100 101// --------------------------------------------------------------------------- 102// Piano / Chartbeat conversion events 103// --------------------------------------------------------------------------- 104//window.tp = window.tp || []; 105 106// EVENT 1 â User identified as subscriber (REQUIRED) 107/*window.tp.push(['addHandler', 'userSegmentTrue', function (params) { 108 if (window.pSUPERFLY) { 109 pSUPERFLY.virtualPage({ 110 path: window.location.pathname, 111 sections: window._sf_async_config.sections || '', 112 authors: window._sf_async_config.authors || '', 113 type: 'paidContent' 114 }); 115 } 116 chartbeat('trackSubscriberStatus', { status: 'subscriber' }); 117}]);*/ 118 119// EVENT 1b â User identified as non-subscriber (REQUIRED) 120/*window.tp.push(['addHandler', 'userSegmentFalse', function (params) { 121 if (window.pSUPERFLY) { 122 pSUPERFLY.virtualPage({ 123 path: window.location.pathname, 124 sections: window._sf_async_config.sections || '', 125 authors: window._sf_async_config.authors || '', 126 type: 'content' 127 }); 128 } 129 chartbeat('trackSubscriberStatus', { status: 'non-subscriber' }); 130}]);*/ 131 132// EVENT 2 â User sees the paywall (REQUIRED) 133/*var _cbPaywallAbandonBound = false;
134window.tp.push(['addHandler', 'showOffer', function (params) { 135 if (window.pSUPERFLY) { 136 pSUPERFLY.virtualPage({ 137 path: window.location.pathname, 138 sections: window._sf_async_config.sections || '', 139 authors: window._sf_async_config.authors || '', 140 type: 'gate' 141 }); 142 } 143 chartbeat('trackPaywallShown'); 144 if (!_cbPaywallAbandonBound) { 145 _cbPaywallAbandonBound = true; 146 window.addEventListener('beforeunload', function () { 147 chartbeat('trackPaywallAbandon'); 148 }, { once: true }); 149 } 150}]);*/ 151 152// EVENT 2b â User starts checkout (OPTIONAL) 153/*window.tp.push(['addHandler', 'checkoutStart', function (params) { 154 chartbeat('trackPaywallStart'); 155}]);*/ 156 157// EVENT 3 â User completes subscription (REQUIRED) 158/*window.tp.push(['addHandler', 'checkoutComplete', function (params) { 159 if (window.pSUPERFLY) { 160 pSUPERFLY.virtualPage({ 161 path: window.location.pathname, 162 sections: window._sf_async_config.sections || '', 163 authors: window._sf_async_config.authors || '', 164 type: 'conversion' 165 }); 166 } 167 chartbeat('trackPaywallComplete', { 168 path: window.location.pathname, 169 term: params.termName, 170 offer: params.offerName, 171 }); 172 if (params.isRenewal) { 173 chartbeat('trackRenewal', { term: params.termName }); 174 } 175}]);*/ 176 177// EVENT 3b â User cancels checkout (OPTIONAL) 178/*window.tp.push(['addHandler', 'checkoutClose', function (params) { 179 chartbeat('trackPaywallCancel'); 180}]);*/ 181 182// EVENT â Metered paywall: meter running, user has free articles left (OPTIONAL) 183/*window.tp.push(['addHandler', 'meterActive', function (params) { 184 chartbeat('track', 'meter_active', { 185 current: params.currentCount, 186 max: params.maxCount 187 }); 188}]); 189 190// EVENT â Metered paywall: meter exhausted (OPTIONAL) 191window.tp.push(['addHandler', 'meterExpired', function (params) { 192 chartbeat('track', 'meter_expired', { 193 max: params.maxCount 194 }); 195}]); 196 197// EVENT â Piano requires login to access content (OPTIONAL) 198window.tp.push(['addHandler', 'loginRequired', function (params) { 199 chartbeat('track', 'login_required'); 200}]); 201 202// EVENT â User logged in via Piano overlay (OPTIONAL) 203window.tp.push(['addHandler', 'loginSuccess', function (params) { 204 chartbeat('track', 'login_success'); 205}]); 206 207// EVENT â User registered via Piano overlay (OPTIONAL) 208window.tp.push(['addHandler', 'registrationSuccess', function (params) { 209 chartbeat('track', 'registration_success'); 210}]); 211 212// EVENT â Piano experience executed (OPTIONAL) 213window.tp.push(['addHandler', 'experienceExecute', function (params) { 214 chartbeat('track', 'experience_execute', { 215 id: params.experienceId 216 }); 217}]);*/ 218 219// --------------------------------------------------------------------------- 220// Engagement events 221// --------------------------------------------------------------------------- 222/*document.addEventListener('DOMContentLoaded', function () { 223 224 // Click on related articles 225 document.querySelectorAll('.articoli-correlati a, .related a').forEach(function (link) { 226 link.addEventListener('click', function () { 227 chartbeat('track', 'related_article_click', { 228 from: window.location.pathname, 229 to: this.getAttribute('href') 230 }); 231 }); 232 }); 233 234 // Scroll depth milestones â 25 / 50 / 75 / 100% 235 (function () { 236 var milestones = [25, 50, 75, 100]; 237 var fired = {}; 238 function getScrollPercent() { 239 var scrollTop = window.pageYOffset || document.documentElement.scrollTop; 240 var docHeight = Math.max( 241 document.body.scrollHeight, 242 document.documentElement.scrollHeight 243 ) - window.innerHeight; 244 return docHeight > 0 ? Math.round((scrollTop / docHeight) * 100) : 100; 245 } 246 window.addEventListener('scroll', function () { 247 var pct = getScrollPercent(); 248 milestones.forEach(function (m) { 249 if (!fired[m] && pct >= m) { 250 fired[m] = true; 251 chartbeat('track', 'scroll_depth', { depth: m }); 252 } 253 }); 254 }, { passive: true }); 255 })(); 256 257 // Social share clicks â network detected from share-icon--* class 258 document.addEventListener('click', function (e) { 259 var link = e.target.closest('.magazine-article-share-popup a'); 260 if (!link) { 261 return; 262 } 263 var iconEl = link.querySelector('[class*="share-icon--"]'); 264 var network = 'unknown'; 265 if (iconEl) { 266 var match = iconEl.className.match(/share-icon--(\S+)/); 267 if (match) { 268 network = match[1]; 269 } 270 } 271 chartbeat('track', 'social_share', { 272 network: network, 273 path: window.location.pathname 274 }); 275 }); 276 277 // Outbound link clicks â article content only, excludes on-site navigation 278 document.addEventListener('click', function (e) { 279 var link = e.target.closest('article a, .hentry a'); 280 if (!link) { 281 return; 282 } 283 if (link.hostname && link.hostname !== window.location.hostname) { 284 chartbeat('track', 'outbound_click', { 285 to: link.hostname, 286 from: window.location.pathname 287 }); 288 } 289 }); 290 291});*/
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.