PageSourceSearch

https://www.knest.ai/blog/knest-blog-archive.js

js knest.ai collected 2026-10-05 13:09:40 UTC 3,253 bytes, 120 lines download raw bytes

1(function () {
2  var PER_PAGE = 6;
3  var grid = document.getElementById("kb-articles");
4  var nav = document.getElementById("kb-pagination");
5  var status = document.getElementById("kb-page-status");
6  if (!grid || !nav) return;
7
8  var cards = Array.prototype.slice.call(grid.querySelectorAll(".kb-rec-card"));
9  var total = cards.length;
10  var pages = Math.ceil(total / PER_PAGE);
11  var current = 1;
12
13  var countNum = document.getElementById("kb-count-num");
14  var countLabel = document.getElementById("kb-count-label");
15  if (countNum) countNum.textContent = String(total);
16  if (countLabel) countLabel.textContent = total === 1 ? "article" : "articles";
17
18  if (pages <= 1) return;
19
20  function showPage(n) {
21    current = Math.min(Math.max(1, n), pages);
22    var start = (current - 1) * PER_PAGE;
23    var end = start + PER_PAGE;
24    cards.forEach(function (card, i) {
25      card.hidden = i < start || i >= end;
26    });
27    render();
28    if (status) {
29      var first = start + 1;
30      var last = Math.min(end, total);
31      status.hidden = false;
32      status.textContent = "Showing " + first + "–" + last + " of " + total + " articles";
33    }
34    window.scrollTo({ top: 0, behavior: "smooth" });
35  }
36
37  function makeBtn(label, opts) {
38    opts = opts || {};
39    var b = document.createElement("button");
40    b.type = "button";
41    b.className = "kb-page-btn";
42    b.textContent = label;
43    if (opts.ariaLabel) b.setAttribute("aria-label", opts.ariaLabel);
44    if (opts.disabled) b.disabled = true;
45    if (opts.current) b.setAttribute("aria-current", "page");
46    if (opts.onClick && !opts.disabled && !opts.current) b.addEventListener("click", opts.onClick);
47    return b;
48  }
49
50  function ellipsis() {
51    var s = document.createElement("span");
52    s.className = "kb-page-ellipsis";
53    s.textContent = "…";
54    s.setAttribute("aria-hidden", "true");
55    return s;
56  }
57
58  function pageList() {
59    var set = {};
60    set[1] = true;
61    set[pages] = true;
62    for (var d = -1; d <= 1; d++) {
63      var p = current + d;
64      if (p >= 1 && p <= pages) set[p] = true;
65    }
66    var nums = Object.keys(set)
67      .map(Number)
68      .sort(function (a, b) {
69        return a - b;
70      });
71    var out = [];
72    var prev = 0;
73    nums.forEach(function (n) {
74      if (prev && n - prev > 1) out.push("gap");
75      out.push(n);
76      prev = n;
77    });
78    return out;
79  }
80
81  function render() {
82    nav.hidden = false;
83    nav.innerHTML = "";
84    nav.appendChild(
85      makeBtn("‹ Prev", {
86        ariaLabel: "Previous page",
87        disabled: current === 1,
88        onClick: function () {
89          showPage(current - 1);
90        },
91      }),
92    );
93    pageList().forEach(function (item) {
94      if (item === "gap") {
95        nav.appendChild(ellipsis());
96        return;
97      }
98      nav.appendChild(
99        makeBtn(String(item), {
100          ariaLabel: "Page " + item,
101          current: item === current,
102          onClick: function () {
103            showPage(item);
104          },
105        }),
106      );
107    });
108    nav.appendChild(
109      makeBtn("Next ›", {
110        ariaLabel: "Next page",
111        disabled: current === pages,
112        onClick: function () {
113          showPage(current + 1);
114        },
115      }),
116    );
117  }
118
119  showPage(1);
120})();

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.