docs/static/js/ui.js (3135B)
1 /* Chrome that needs the viewport or the scroll position to decide.
2 *
3 * Everything here degrades to a usable page when it does not run: the sidebar
4 * stays open, and the table of contents stays a plain list of links.
5 */
6 (function () {
7 /* The sidebar ships open so that a page without JavaScript is complete. On a
8 narrow screen that means a long list before the content, so close it —
9 but only there, and only once, before anything is painted. */
10 var drawer = document.getElementById("nav-drawer");
11 if (drawer && matchMedia("(max-width: 60rem)").matches) {
12 drawer.open = false;
13 }
14
15 /* Mark the heading the reader is currently under.
16 rootMargin pins the trigger line near the top of the viewport: without it
17 a heading counts as "visible" while it is still at the bottom of the
18 screen, and the marker runs ahead of the reader. */
19 var links = document.querySelectorAll(".toc a[href^='#']");
20 if (!links.length || !("IntersectionObserver" in window)) return;
21
22 var byId = {};
23 var headings = [];
24 links.forEach(function (a) {
25 var id = decodeURIComponent(a.getAttribute("href").slice(1));
26 var h = document.getElementById(id);
27 if (!h) return;
28 byId[id] = a;
29 headings.push(h);
30 });
31
32 var current = null;
33 var seen = {};
34
35 function mark() {
36 // 가장 위에 있는, 이미 지나온 제목이 지금 읽는 곳이다.
37 var best = null;
38 headings.forEach(function (h) {
39 if (seen[h.id]) best = h;
40 });
41 if (!best || best === current) return;
42 if (current && byId[current.id]) byId[current.id].removeAttribute("aria-current");
43 byId[best.id].setAttribute("aria-current", "true");
44 current = best;
45 }
46
47 var io = new IntersectionObserver(
48 function (entries) {
49 entries.forEach(function (e) {
50 seen[e.target.id] = e.boundingClientRect.top < 0 || e.isIntersecting;
51 });
52 mark();
53 },
54 { rootMargin: "-10% 0px -70% 0px", threshold: 0 }
55 );
56 headings.forEach(function (h) { io.observe(h); });
57 })();
58
59 /* Copy buttons on code blocks.
60 *
61 * The documentation says line numbers and a copy button are the site's own CSS
62 * and JavaScript rather than configuration keys. This is that claim, kept.
63 */
64 (function () {
65 var s = document.currentScript || document.querySelector("script[data-copy]");
66 var COPY = (s && s.dataset.copy) || "Copy";
67 var DONE = (s && s.dataset.copied) || "Copied";
68 if (!navigator.clipboard) return;
69
70 document.querySelectorAll(".prose pre.highlight").forEach(function (pre) {
71 var code = pre.querySelector("code");
72 if (!code) return;
73 var b = document.createElement("button");
74 b.type = "button";
75 b.className = "copy";
76 b.textContent = COPY;
77 b.addEventListener("click", function () {
78 // pre.textContent를 쓰면 버튼 자신의 라벨까지 복사된다.
79 navigator.clipboard.writeText(code.textContent).then(function () {
80 b.textContent = DONE;
81 b.dataset.done = "";
82 setTimeout(function () {
83 b.textContent = COPY;
84 delete b.dataset.done;
85 }, 1200);
86 });
87 });
88 pre.appendChild(b);
89 });
90 })();