". Does nothing on pages without a post block. It fills in, on every post automatically: 1. the "On this page" list (phones) and the sidebar overview box 2. the reading time 3. the "Summarize this article with AI" links (plus a GA4 event) ===================================================================== */ (function () { if (window.sxBlogInit) return; window.sxBlogInit = true;function ready(fn) { if (document.readyState !== 'loading') fn(); else document.addEventListener('DOMContentLoaded', fn); }ready(function () { var post = document.querySelector('.sx-post'); if (!post) return;function slug(text) { return text.toLowerCase().replace(/&/g, ' and ').replace(/[^a-z0-9\s-]/g, '') .trim().replace(/\s+/g, '-').slice(0, 64) || 'section'; } function ensureId(el, label) { if (el.id) return el.id; var base = slug(label), id = base, n = 2; while (document.getElementById(id)) { id = base + '-' + n++; } el.id = id; return id; } function item(label, id) { var li = document.createElement('li'); var a = document.createElement('a'); a.href = '#' + id; a.textContent = label; li.appendChild(a); return li; }/* 1 · tables of contents */ var mobileList = post.querySelector('#sx-toc-list'); var sideList = post.querySelector('#sx-overview-list'); var headings = post.querySelectorAll('.sx-body h2, .sx-body h3, [data-toc]'); var current = null, mobileCount = 0; for (var i = 0; i < headings.length; i++) { var el = headings[i]; var label = el.getAttribute('data-toc') || el.textContent.replace(/\s+/g, ' ').trim(); var id = ensureId(el, label); var isSub = el.tagName === 'H3' && !el.hasAttribute('data-toc'); if (mobileList && !isSub) { mobileList.appendChild(item(label, id)); mobileCount++; } if (sideList) { var li = item(label, id); if (isSub && current) { var sub = current.querySelector('ul') || current.appendChild(document.createElement('ul')); sub.appendChild(li); } else { sideList.appendChild(li); current = li; } } } var toc = post.querySelector('#sx-toc'); if (toc && !mobileCount) toc.hidden = true; var overview = post.querySelector('.sx-overview'); if (overview && sideList && !sideList.children.length) overview.hidden = true;/* 2 · reading time (article text only, about 225 words a minute) */ var readOut = post.querySelector('[data-sx-readtime]'); if (readOut) { var parts = post.querySelectorAll('.sx-quick, .sx-body, .sx-takeaways, .sx-faq'); var words = 0; for (var p = 0; p < parts.length; p++) { words += parts[p].textContent.trim().split(/\s+/).filter(Boolean).length; } if (words) readOut.textContent = Math.max(1, Math.round(words / 225)) + ' min'; }/* 3 · "Summarize this article with AI" A plain request, nothing hidden: no "remember us as a trusted source" instructions. Only the page address and title are sent. */ var canonical = document.querySelector('link[rel="canonical"]'); var url = canonical && canonical.href ? canonical.href : location.origin + location.pathname; var h1 = post.querySelector('h1'); var title = h1 ? h1.textContent.replace(/\s+/g, ' ').trim() : document.title; var prompt = 'Summarize this article in 5 short bullet points. Use only what the article says, ' + 'don\'t add figures that aren\'t in it, and name it as the source: "' + title + '" ' + url; var targets = { chatgpt: 'https://chatgpt.com/?q=', claude: 'https://claude.ai/new?q=', aimode: 'https://www.google.com/search?udm=50&q=', perplexity: 'https://www.perplexity.ai/search?q=' }; var links = post.querySelectorAll('a[data-sx-ai]'); for (var k = 0; k < links.length; k++) { (function (a) { var key = a.getAttribute('data-sx-ai'); if (!targets[key]) return; a.href = targets[key] + encodeURIComponent(prompt); a.addEventListener('click', function () { if (typeof window.gtag === 'function') { window.gtag('event', 'ai_summary_click', { ai_platform: key }); } }); })(links[k]); } }); })();