1/* News & blog: announcements open in a reader on the page (and by link: #news-<name>), the sticky bar follows the 2 section in view. Blog articles and topics link to netsecurity.com, where the blog itself still lives. */ 3(function () { 4 'use strict'; 5 6 const header = document.querySelector('.hdx'); 7 const bar = document.querySelector('.nb-bar'); 8 const dlg = document.querySelector('.nb-reader'); 9 10 function measure() { 11 document.body.style.setProperty('--nb-header', (header ? header.getBoundingClientRect().height + Math.min(0, parseFloat(getComputedStyle(header).top) || 0) : 76) + 'px'); 12 } 13 14 window.addEventListener('resize', measure); 15 measure(); 16 17 /* ---- the bar marks the section in view ---- */ 18 const tabs = Array.from(document.querySelectorAll('.nb-tabs a')); 19 const secs = tabs.map(function (a) { return document.querySelector(a.getAttribute('href')); }); 20 21 function spy() { 22 const line = (bar ? bar.getBoundingClientRect().bottom : 0) + 60; 23 let cur = 0; 24 25 secs.forEach(function (s, i) { if (s && s.getBoundingClientRect().top <= line) cur = i; }); 26
27 tabs.forEach(function (a, i) { 28 if (i === cur) a.setAttribute('aria-current', 'true'); 29 else a.removeAttribute('aria-current'); 30 }); 31 } 32 33 window.addEventListener('scroll', spy, { passive: true }); 34 spy(); 35 36 /* ---- the reader ---- */ 37 if (!dlg || typeof dlg.showModal !== 'function') return; 38 const body = dlg.querySelector('.nb-reader-body'); 39 let back = null; 40 41 function open(name, remember) { 42 const t = document.getElementById('nb-a-' + name); 43 44 if (!t) return; 45 body.innerHTML = ''; 46 body.appendChild(t.content.cloneNode(true)); 47 48 const title = body.querySelector('.nb-r-title'); 49 50 if (title) title.id = 'nb-reader-title'; 51 if (window.PUI) body.querySelectorAll('[data-ic]').forEach(function (el) { el.innerHTML = window.PUI.icon(el.getAttribute('data-ic')); }); 52 body.querySelectorAll('a[href^="http"]').forEach(function (a) { a.target = '_blank'; a.rel = 'noopener'; }); 53 back = document.activeElement; 54 dlg.showModal(); 55 body.scrollTop = 0; 56 if (remember) history.replaceState(null, '', location.pathname + location.search + '#news-' + name); 57 } 58 59 document.addEventListener('click', function (e) { 60 const o = e.target.closest('[data-open]'); 61 62 if (!o || e.target.closest('a')) return; 63 e.preventDefault(); 64 open(o.getAttribute('data-open'), true); 65 }); 66 67 dlg.querySelector('.nb-x').addEventListener('click', function () { dlg.close(); }); 68 dlg.addEventListener('click', function (e) { if (e.target === dlg) dlg.close(); }); 69 70 dlg.addEventListener('close', function () { 71 if (/^#news-/.test(location.hash)) history.replaceState(null, '', location.pathname + location.search + '#news'); 72 if (back && back.focus) back.focus({ preventScroll: true }); 73 }); 74 75 const m = location.hash.match(/^#news-([a-z0-9-]+)$/); 76 77 if (m) window.addEventListener('load', function () { open(m[1], false); }); 78})();
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.