PageSourceSearch

https://happystarkitty.github.io/js/pjax_script.js

js happystarkitty.github.io collected 2026-10-03 09:16:49 UTC 13,978 bytes, 469 lines download raw bytes

1var getRealPath = (pathname = window.location.pathname, desc = false) => {
2  const names = pathname.split("/").filter((name) => {
3    name = name.trim();
4    return name.length > 0 && name !== "/" && name !== "index.html";
5  });
6  if (desc) {
7    return names[0] || "/";
8  } else {
9    return names[names.length - 1] || "/";
10  }
11};
12
13var scrollIntoViewAndWait = (element) => {
14  return new Promise((resolve) => {
15    if ("onscrollend" in window) {
16      document.addEventListener("scrollend", resolve, { once: true });
17      element.scrollIntoView({
18        behavior: "smooth",
19        block: "center",
20        inline: "center",
21      });
22    } else {
23      element.scrollIntoView({ block: "center", inline: "center" });
24      resolve();
25    }
26  });
27};
28
29// anchor
30_$$(
31  ".article-entry h1>a:first-of-type, .article-entry h2>a:first-of-type, .article-entry h3>a:first-of-type, .article-entry h4>a:first-of-type, .article-entry h5>a:first-of-type, .article-entry h6>a:first-of-type"
32).forEach((element) => {
33  if (window.REIMU_CONFIG.icon_font) {
34    // iconfont
35    element.innerHTML = window.REIMU_CONFIG.anchor_icon
36      ? `&#x${window.REIMU_CONFIG.anchor_icon};`
37      : window.REIMU_CONFIG.anchor_icon === false
38      ? ""
39      : "";
40  } else {
41    // fontawesome
42    element.innerHTML = window.REIMU_CONFIG.anchor_icon
43      ? `&#x${window.REIMU_CONFIG.anchor_icon};`
44      : window.REIMU_CONFIG.anchor_icon === false
45      ? ""
46      : "";
47  }
48});
49
50// lightbox
51_$$(".article-entry img").forEach((element) => {
52  if (
53    element.parentElement.classList.contains("friend-icon") ||
54    element.parentElement.tagName === "A" ||
55    element.classList.contains("no-lightbox")
56  )
57    return;
58  const a = document.createElement("a");
59  a.href ? (a.href = element.src) : a.setAttribute("href", element.src);
60  if (element.naturalWidth || element.naturalHeight) {
61    a.dataset.pswpWidth = element.naturalWidth;
62    a.dataset.pswpHeight = element.naturalHeight;
63  } else {
64    console.warn(
65      "Image naturalWidth and naturalHeight cannot be obtained right now, fallback to onload."
66    );
67    element.onload = () => {
68      a.dataset.pswpWidth = element.naturalWidth;
69      a.dataset.pswpHeight = element.naturalHeight;
70    };
71  }
72  a.target = "_blank";
73  a.classList.add("article-gallery-item");
74  element.parentNode.insertBefore(a, element);
75  element.parentNode.removeChild(element);
76  a.appendChild(element);
77});
78window.lightboxStatus = "ready";
79window.dispatchEvent(new Event("lightbox:ready"));
80
81// table wrap
82_$$(".article-entry table").forEach((element) => {
83  if (element.closest("figure.highlight")) return;
84  const wrapper = document.createElement("div");
85  wrapper.classList.add("table-wrapper");
86  element.parentNode?.insertBefore(wrapper, element);
87  element.parentNode?.removeChild(element);
88  wrapper.appendChild(element);
89});
90
91// wrap details content for old @reimujs/hexo-renderer-markdown-it-plus
92_$$(".article-entry details.custom-block").forEach((element) => {
93  if (element.querySelector(".detail-content")) return;
94  const summary = element.querySelector("summary");
95  if (!summary) return;
96  const detailContent = document.createElement("div");
97  detailContent.classList.add("detail-content");
98  
99  const range = document.createRange();
100  range.setStartAfter(summary);
101  range.setEndAfter(element.lastChild);
102  detailContent.appendChild(range.extractContents());
103  
104  element.appendChild(detailContent);
105});
106
107// Mobile nav
108var isMobileNavAnim = false;
109
110_$("#main-nav-toggle")
111  .off("click")
112  .on("click", () => {
113    if (isMobileNavAnim) return;
114    isMobileNavAnim = true;
115    document.body.classList.toggle("mobile-nav-on");
116    _$("#mask").classList.remove("hide");
117    setTimeout(() => {
118      isMobileNavAnim = false;
119    }, 300);
120  });
121
122_$("#mask")
123  ?.off("click")
124  .on("click", () => {
125    if (isMobileNavAnim || !document.body.classList.contains("mobile-nav-on"))
126      return;
127    document.body.classList.remove("mobile-nav-on");
128    _$("#mask").classList.add("hide");
129  });
130
131_$$(".sidebar-toc-btn").forEach((element) => {
132  element.off("click").on("click", function () {
133    if (this.classList.contains("current")) return;
134    _$$(".sidebar-toc-btn").forEach((element) =>
135      element.classList.add("current")
136    );
137    _$$(".sidebar-common-btn").forEach((element) =>
138      element.classList.remove("current")
139    );
140    _$$(".sidebar-toc-sidebar").forEach((element) =>
141      element.classList.remove("hidden")
142    );
143    _$$(".sidebar-common-sidebar").forEach((element) =>
144      element.classList.add("hidden")
145    );
146  });
147});
148
149_$$(".sidebar-common-btn").forEach((element) => {
150  element.off("click").on("click", function () {
151    if (this.classList.contains("current")) return;
152    _$$(".sidebar-common-btn").forEach((element) =>
153      element.classList.add("current")
154    );
155    _$$(".sidebar-toc-btn").forEach((element) =>
156      element.classList.remove("current")
157    );
158    _$$(".sidebar-common-sidebar").forEach((element) =>
159      element.classList.remove("hidden")
160    );
161    _$$(".sidebar-toc-sidebar").forEach((element) =>
162      element.classList.add("hidden")
163    );
164  });
165});
166
167(() => {
168  const rootRealPath = getRealPath(window.location.pathname);
169  _$$(".sidebar-menu-link-wrap").forEach((link) => {
170    let linkPath = link.querySelector("a").getAttribute("href");
171    if (linkPath && getRealPath(linkPath) === rootRealPath) {
172      link.classList.add("link-active");
173    }
174  });
175})();
176
177// lazyload
178_$$(".article-entry img").forEach((element) => {
179  if (element.classList.contains("lazyload")) return;
180  element.classList.add("lazyload");
181  element.setAttribute("data-src", element.src);
182  element.setAttribute("data-sizes", "auto");
183  element.removeAttribute("src");
184});
185
186// to top
187var sidebarTop = _$(".sidebar-top");
188if (sidebarTop) {
189  sidebarTop.style.transition = "all .3s";
190  sidebarTop.off("click").on("click", () => {
191    window.scrollTo({
192      top: 0,
193      behavior: "smooth",
194    });
195  });
196  if (document.documentElement.scrollTop < 10) {
197    sidebarTop.style.opacity = 0;
198  }
199}
200
201var __sidebarTopScrollHandler;
202
203if (__sidebarTopScrollHandler) {
204  window.off("scroll", __sidebarTopScrollHandler);
205}
206
207__sidebarTopScrollHandler = () => {
208  const sidebarTop = _$(".sidebar-top");
209  if (document.documentElement.scrollTop < 10) {
210    sidebarTop.style.opacity = 0;
211  } else {
212    sidebarTop.style.opacity = 1;
213  }
214};
215
216window.on("scroll", __sidebarTopScrollHandler);
217
218// toc
219_$$("#mobile-nav .toc li").forEach((element) => {
220  element.off("click").on("click", () => {
221    if (isMobileNavAnim || !document.body.classList.contains("mobile-nav-on"))
222      return;
223    document.body.classList.remove("mobile-nav-on");
224    _$("#mask").classList.add("hide");
225  });
226});
227
228_$$("#mobile-nav .sidebar-menu-link-dummy").forEach((element) => {
229  element.off("click").on("click", () => {
230    if (isMobileNavAnim || !document.body.classList.contains("mobile-nav-on"))
231      return;
232    setTimeout(() => {
233      document.body.classList.remove("mobile-nav-on");
234      _$("#mask").classList.add("hide");
235    }, 200);
236  });
237});
238
239function tocInit() {
240  if (!_$("#sidebar")) return;
241  const navItems =
242    getComputedStyle(_$("#sidebar")).display === "block"
243      ? _$$("#sidebar .sidebar-toc-wrapper li")
244      : _$$("#mobile-nav .sidebar-toc-wrapper li");
245  if (!navItems.length) return;
246
247  let activeLock = null;
248
249  const anchorScroll = (event, index) => {
250    event.preventDefault();
251    const target = document.getElementById(
252      decodeURI(event.currentTarget.getAttribute("href")).slice(1)
253    );
254    activeLock = index;
255    scrollIntoViewAndWait(target).then(() => {
256      activateNavByIndex(index);
257      activeLock = null;
258    });
259  };
260
261  const sections = [...navItems].map((element, index) => {
262    const link = element.querySelector("a.toc-link");
263    link.off("click").on("click", (e) => anchorScroll(e, index));
264    const anchor = document.getElementById(
265      decodeURI(link.getAttribute("href")).slice(1)
266    );
267    if (!anchor) return null;
268    const alink = anchor.querySelector("a");
269    alink?.off("click").on("click", (e) => anchorScroll(e, index));
270    return anchor;
271  });
272
273  const activateNavByIndex = (index) => {
274    const target = navItems[index];
275
276    if (!target || target.classList.contains("current")) return;
277
278    _$$(".sidebar-toc-wrapper .active").forEach((element) => {
279      element.classList.remove("active", "current");
280    });
281
282    sections.forEach((element) => {
283      element?.classList.remove("active");
284    });
285
286    target.classList.add("active", "current");
287    sections[index]?.classList.add("active");
288
289    let parent = target.parentNode;
290
291    while (!parent.matches(".sidebar-toc-sidebar")) {
292      if (parent.matches("li")) {
293        parent.classList.add("active");
294        const t = document.getElementById(
295          decodeURI(
296            parent.querySelector("a.toc-link").getAttribute("href").slice(1)
297          )
298        );
299        if (t) {
300          t.classList.add("active");
301        }
302      }
303      parent = parent.parentNode;
304    }
305    // Scrolling to center active TOC element if TOC content is taller than viewport.
306    if (!_$(".sidebar-toc-sidebar").classList.contains("hidden")) {
307      const tocWrapper = _$(".sidebar-toc-wrapper");
308      tocWrapper.scrollTo({
309        top:
310          tocWrapper.scrollTop + target.offsetTop - tocWrapper.offsetHeight / 2,
311        behavior: "smooth",
312      });
313    }
314  };
315
316  const findIndex = (entries) => {
317    let index = 0;
318    let entry = entries[index];
319
320    if (entry.boundingClientRect.top > 0) {
321      index = sections.indexOf(entry.target);
322      return index === 0 ? 0 : index - 1;
323    }
324    for (; index < entries.length; index++) {
325      if (entries[index].boundingClientRect.top <= 0) {
326        entry = entries[index];
327      } else {
328        return sections.indexOf(entry.target);
329      }
330    }
331    return sections.indexOf(entry.target);
332  };
333
334  const observer = new IntersectionObserver(
335    (entries) => {
336      const index = findIndex(entries) + (window.diffY > 0 ? 1 : 0);
337      if (activeLock === null) {
338        activateNavByIndex(index);
339      }
340    },
341    {
342      rootMargin: "0px 0px -100% 0px",
343      threshold: 0,
344    }
345  );
346
347  sections.forEach((element) => {
348    element && observer.observe(element);
349  });
350}
351
352// hexo-blog-encrypt
353window
354  .off("hexo-blog-decrypt")
355  .on("hexo-blog-decrypt", tocInit)
356  .on("hexo-blog-decrypt", () => {
357    const script = document.createElement("script");
358    script.src = "/js/insert_highlight.js";
359    script.setAttribute("data-pjax", true);
360    document.body.appendChild(script);
361  });
362tocInit();
363
364_$(".sponsor-button")
365  ?.off("click")
366  .on("click", () => {
367    _$(".sponsor-button")?.classList.toggle("active");
368    _$(".sponsor-tip")?.classList.toggle("active");
369    _$(".sponsor-qr")?.classList.toggle("active");
370  });
371
372var shareWeixinHandler;
373if (shareWeixinHandler) {
374  document.off("click", shareWeixinHandler);
375}
376shareWeixinHandler = (e) => {
377  if (e.target.closest(".share-icon.icon-weixin")) return;
378  const sw = _$("#share-weixin");
379  if (sw && sw.classList.contains("active")) {
380    sw.classList.remove("active");
381    sw.addEventListener(
382      "transitionend",
383      function handler() {
384        sw.style.display = "none";
385        sw.removeEventListener("transitionend", handler);
386      },
387      { once: true },
388    );
389  }
390};
391document.on("click", shareWeixinHandler);
392
393_$(".share-icon.icon-weixin")
394  ?.off("click")
395  .on("click", function (e) {
396    const iconPosition = this.getBoundingClientRect();
397    const shareWeixin = this.querySelector("#share-weixin");
398
399    if (iconPosition.x - 148 < 0) {
400      shareWeixin.style.left = `-${iconPosition.x - 10}px`;
401    } else if (iconPosition.x + 172 > window.innerWidth) {
402      shareWeixin.style.left = `-${310 - window.innerWidth + iconPosition.x}px`;
403    } else {
404      shareWeixin.style.left = "-138px";
405    }
406    if (e.target === this) {
407      const el = shareWeixin;
408      if (!el) return;
409      if (!el.classList.contains("active")) {
410        el.style.display = "block";
411        requestAnimationFrame(() => {
412          el.classList.add("active");
413        });
414      } else {
415        el.classList.remove("active");
416        const onEnd = (ev) => {
417          if (ev.propertyName === "opacity") {
418            el.style.display = "none";
419            el.removeEventListener("transitionend", onEnd);
420          }
421        };
422        el.addEventListener("transitionend", onEnd);
423      }
424    }
425    // if contains img return
426    if (_$(".share-weixin-canvas").children.length) {
427      return;
428    }
429    const { cover, excerpt, description, title, stripContent, author } =
430      window.REIMU_POST;
431    _$("#share-weixin-banner").src = cover;
432    _$("#share-weixin-title").innerText = title;
433    _$("#share-weixin-desc").innerText = excerpt || description || str
433ipContent;
434    _$("#share-weixin-author").innerText = "By: " + author;
435    QRCode.toDataURL(window.REIMU_POST.url, function (error, dataUrl) {
436      if (error) {
437        console.error(error);
438        return;
439      }
440      _$("#share-weixin-qr").src = dataUrl;
441      snapdom
442        .toPng(_$(".share-weixin-dom"))
443        .then((img) => {
444          _$(".share-weixin-canvas").appendChild(img);
445        })
446        .catch(() => {
447          // we assume that the error is caused by the browser's security policy
448          // so we will remove the banner and try again
449          _$("#share-weixin-banner").remove();
450          snapdom
451            .toPng(_$(".share-weixin-dom"))
452            .then((img) => {
453              _$(".share-weixin-canvas").appendChild(img);
454            })
455            .catch(() => {
456              console.error("Failed to generate weixin share image.");
457            });
458        });
459    });
460  });
461
462var imgElement = _$("#header > img");
463if (imgElement.src || imgElement.style.background) {
464  window.bannerElement = imgElement;
465} else {
466  window.bannerElement = _$("#header > picture img");
467}
468
469window.generateSchemeHandler?.();

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.