PageSourceSearch

https://zerorank.ai/assets/js/blog.js?v=20260923-7

js zerorank.ai collected 2026-09-30 10:43:52 UTC 3,775 bytes, 86 lines download raw bytes

1/* Blog article behaviour (legacy blog-post.html:6991–7082): the table-of-contents scroll-spy and
2   the share buttons. Nothing else lives here — the newsletter form is forms.js. */
3(function () {
4  'use strict';
5
6  /* ── table of contents ────────────────────────────────────────────────
7     Marks the section you are actually reading. rootMargin pulls the
8     trigger line down to roughly a third of the viewport so the highlight
9     changes when a heading reaches reading position, not when it grazes
10     the top edge. */
11  var toc = document.getElementById('zr-toc');
12  if (toc && 'IntersectionObserver' in window) {
13    var links = {};
14    toc.querySelectorAll('a[href^="#"]').forEach(function (a) {
15      links[a.getAttribute('href').slice(1)] = a;
16    });
17    var targets = Object.keys(links)
18      .map(function (id) { return document.getElementById(id); })
19      .filter(Boolean);
20
21    var mark = function (id) {
22      Object.keys(links).forEach(function (k) {
23        links[k].classList.toggle('is-here', k === id);
24      });
25    };
26
27    var seen = new Set();
28    var io = new IntersectionObserver(function (entries) {
29      entries.forEach(function (e) {
30        if (e.isIntersecting) seen.add(e.target.id); else seen.delete(e.target.id);
31      });
32      /* the topmost heading currently in the band wins */
33      for (var i = 0; i < targets.length; i++) {
34        if (seen.has(targets[i].id)) { mark(targets[i].id); return; }
35      }
36    }, { rootMargin: '-110px 0px -66% 0px' });
37    targets.forEach(function (t) { io.observe(t); });
38  }
39
40  /* ── share ────────────────────────────────────────────────────────────
41     The intent URLs are rendered server-side into data-href (so the
42     shared URL is the canonical one, never an empty string); the copy
43     mirrors the MCP pill: async clipboard first, a hidden textarea behind
44     it, and the tick only shows if one of them actually reported success. */
45  var open = function (href) {
46    window.open(href, '_blank', 'noopener,noreferrer,width=620,height=640');
47  };
48  document.querySelectorAll('.zr-art__share button[data-href]').forEach(function (btn) {
49    btn.addEventListener('click', function () { open(btn.getAttribute('data-href')); });
50  });
51
52  var copyBtn = document.getElementById('zr-share-copy');
53  if (copyBtn) {
54    var url = copyBtn.getAttribute('data-copy') || location.href.split('#')[0];
55    var fallback = function (text) {
56      var ta = document.createElement('textarea');
57      ta.value = text;
58      ta.setAttribute('readonly', '');
59      ta.style.cssText = 'position:fixed;top:0;left:-9999px;opacity:0';
60      document.body.appendChild(ta);
61      ta.select();
62      var ok = false;
63      try { ok = document.execCommand('copy'); } catch (err) { ok = false; }
64      document.body.removeChild(ta);
65      return ok;
66    };
67    var timer, flag = function (ok) {
68      clearTimeout(timer);
69      copyBtn.classList.toggle('is-copied', ok);
70      copyBtn.setAttribute('aria-label', ok ? 'Link copied' : 'Copy link to this article');
71      if (!ok) return;
72      timer = setTimeout(function () {
73        copyBtn.classList.remove('is-copied');
74        copyBtn.setAttribute('aria-label', 'Copy link to this article');
75      }, 1800);
76    };
77    copyBtn.addEventListener('click', function () {
78      if (navigator.clipboard && navigator.clipboard.writeText) {
79        navigator.clipboard.writeText(url).then(function () { flag(true); })
80          .catch(function () { flag(fallback(url)); });
81      } else {
82        flag(fallback(url));
83      }
84    });
85  }
86})();

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.