PageSourceSearch

https://hihopkc.github.io/js/main.js

js hihopkc.github.io collected 2026-10-03 09:17:47 UTC 61,376 bytes, 1,832 lines download raw bytes

1// 第一次播放音乐
2var anzhiyu_musicFirst = false;
3// 快捷键
4var anzhiyu_keyboard = null;
5// 音乐播放状态
6var anzhiyu_musicPlaying = false;
7var $bodyWrap = document.getElementById("body-wrap");
8var anzhiyu_intype = false;
9var anzhiyu_keyUpEvent_timeoutId = null;
10var anzhiyu_keyUpShiftDelayEvent_timeoutId = null;
11
12var popupWindowTimer = null;
13
14var adjectives = [
15  "美丽的",
16  "英俊的",
17  "聪明的",
18  "勇敢的",
19  "可爱的",
20  "慷慨的",
21  "善良的",
22  "可靠的",
23  "开朗的",
24  "成熟的",
25  "稳重的",
26  "真诚的",
27  "幽默的",
28  "豁达的",
29  "有趣的",
30  "活泼的",
31  "优雅的",
32  "敏捷的",
33  "温柔的",
34  "温暖的",
35  "敬业的",
36  "细心的",
37  "耐心的",
38  "深沉的",
39  "朴素的",
40  "含蓄的",
41  "率直的",
42  "开放的",
43  "务实的",
44  "坚强的",
45  "自信的",
46  "谦虚的",
47  "文静的",
48  "深刻的",
49  "纯真的",
50  "朝气蓬勃的",
51  "慎重的",
52  "大方的",
53  "顽强的",
54  "迷人的",
55  "机智的",
56  "善解人意的",
57  "富有想象力的",
58  "有魅力的",
59  "独立的",
60  "好奇的",
61  "干净的",
62  "宽容的",
63  "尊重他人的",
64  "体贴的",
65  "守信的",
66  "有耐性的",
67  "有责任心的",
68  "有担当的",
69  "有远见的",
70  "有智慧的",
71  "有眼光的",
72  "有冒险精神的",
73  "有爱心的",
74  "有同情心的",
75  "喜欢思考的",
76  "喜欢学习的",
77  "具有批判性思维的",
78  "善于表达的",
79  "善于沟通的",
80  "善于合作的",
81  "善于领导的",
82  "有激情的",
83  "有幽默感的",
84  "有思想的",
85  "有个性的",
86  "有正义感的",
87  "有责任感的",
88  "有创造力的",
89  "有想象力的",
90  "有艺术细胞的",
91  "有团队精神的",
92  "有协调能力的",
93  "有决策能力的",
94  "有组织能力的",
95  "有学习能力的",
96  "有执行能力的",
97  "有分析能力的",
98  "有逻辑思维的",
99  "有创新能力的",
100  "有专业素养的",
101  "有商业头脑的",
102];
103var vegetablesAndFruits = [
104  "萝卜",
105  "白菜",
106  "芹菜",
107  "生菜",
108  "青椒",
109  "辣椒",
110  "茄子",
111  "豆角",
112  "黄瓜",
113  "西红柿",
114  "洋葱",
115  "大蒜",
116  "土豆",
117  "南瓜",
118  "豆腐",
119  "韭菜",
120  "花菜",
121  "西兰花",
122  "蘑菇",
123  "金针菇",
124  "苹果",
125  "香蕉",
126  "橙子",
127  "柠檬",
128  "猕猴桃",
129  "草莓",
130  "葡萄",
131  "桃子",
132  "杏子",
133  "李子",
134  "石榴",
135  "西瓜",
136  "哈密瓜",
137  "蜜瓜",
138  "樱桃",
139  "蓝莓",
140  "柿子",
141  "橄榄",
142  "柚子",
143  "火龙果",
144];
145
146// 已随机的歌曲
147var selectRandomSong = [];
148// 音乐默认声音大小
149var musicVolume = 0.8;
150// 是否切换了周杰伦音乐列表
151var changeMusicListFlag = false;
152// 当前默认播放列表
153var defaultPlayMusicList = [];
154var themeColorMeta, pageHeaderEl, navMusicEl, consoleEl;
155
156document.addEventListener("DOMContentLoaded", function () {
157  let headerContentWidth, $nav, $rightMenu;
158  let mobileSidebarOpen = false;
159
160  const adjustMenu = init => {
161    const getAllWidth = ele => {
162      return Array.from(ele).reduce((width, i) => width + i.offsetWidth, 0);
163    };
164
165    if (init) {
166      const blogInfoWidth = getAllWidth(document.querySelector("#blog_name > a").children);
167      const menusWidth = getAllWidth(document.getElementById("menus").children);
168      headerContentWidth = blogInfoWidth + menusWidth;
169      $nav = document.getElementById("nav");
170    }
171
172    const hideMenuIndex = window.innerWidth <= 768 || headerContentWidth > $nav.offsetWidth - 120;
173    $nav.classList.toggle("hide-menu", hideMenuIndex);
174  };
175
176  // 初始化header
177  const initAdjust = () => {
178    adjustMenu(true);
179    $nav.classList.add("show");
180  };
181
182  // sidebar menus
183  const sidebarFn = {
184    open: () => {
185      anzhiyu.sidebarPaddingR();
186      anzhiyu.animateIn(document.getElementById("menu-mask"), "to_show 0.5s");
187      document.getElementById("sidebar-menus").classList.add("open");
188      mobileSidebarOpen = true;
189    },
190    close: () => {
191      const $body = document.body;
192      $body.style.paddingRight = "";
193      anzhiyu.animateOut(document.getElementById("menu-mask"), "to_hide 0.5s");
194      document.getElementById("sidebar-menus").classList.remove("open");
195      mobileSidebarOpen = false;
196    },
197  };
198
199  /**
200   * 首頁top_img底下的箭頭
201   */
202  const scrollDownInIndex = () => {
203    const handleScrollToDest = () => {
204      const bbTimeList = document.getElementById("bbTimeList");
205      if (bbTimeList) {
206        anzhiyu.scrollToDest(bbTimeList.offsetTop - 62, 300);
207      } else {
208        anzhiyu.scrollToDest(document.getElementById("home_top").offsetTop - 60, 300);
209      }
210    };
211
212    const $scrollDownEle = document.getElementById("scroll-down");
213    $scrollDownEle && anzhiyu.addEventListenerPjax($scrollDownEle, "click", handleScrollToDest);
214  };
215
216  /**
217   * 代码
218   * 只适用于Hexo默认的代码渲染
219   */
220  const addHighlightTool = function () {
221    const highLight = GLOBAL_CONFIG.highlight;
222    if (!highLight) return;
223
224    const isHighlightCopy = highLight.highlightCopy;
225    const isHighlightLang = highLight.highlightLang;
226    const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink;
227    const highlightHeightLimit = highLight.highlightHeightLimit;
228    const isShowTool = isHighlightCopy || isHighlightLang || isHighlightShrink !== undefined;
229    const $figureHighlight =
230      highLight.plugin === "highlighjs"
231        ? document.querySelectorAll("figure.highlight")
232        : document.querySelectorAll('pre[class*="language-"]');
233
234    if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return;
235
236    const isPrismjs = highLight.plugin === "prismjs";
237
238    let highlightShrinkEle = "";
239    let highlightCopyEle = "";
240    const highlightShrinkClass = isHighlightShrink === true ? "closed" : "";
241
242    if (isHighlightShrink !== undefined) {
243      highlightShrinkEle = `<i class="anzhiyufont anzhiyu-icon-angle-down expand ${highlightShrinkClass}"></i>`;
244    }
245
246    if (isHighlightCopy) {
247      highlightCopyEle = '<div class="copy-notice"></div><i class="anzhiyufont anzhiyu-icon-paste copy-button"></i>';
248    }
249
250    const copy = (text, ctx) => {
251      if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
252        document.execCommand("copy");
253        if (GLOBAL_CONFIG.Snackbar !== undefined) {
254          anzhiyu.snackbarShow(GLOBAL_CONFIG.copy.success);
255        } else {
256          const prevEle = ctx.previousElementSibling;
257          prevEle.innerText = GLOBAL_CONFIG.copy.success;
258          prevEle.style.opacity = 1;
259          setTimeout(() => {
260            prevEle.style.opacity = 0;
261          }, 700);
262        }
263      } else {
264        if (GLOBAL_CONFIG.Snackbar !== undefined) {
265          anzhiyu.snackbarShow(GLOBAL_CONFIG.copy.noSupport);
266        } else {
267          ctx.previousElementSibling.innerText = GLOBAL_CONFIG.copy.noSupport;
268        }
269      }
270    };
271
272    // click events
273    const highlightCopyFn = ele => {
274      const $buttonParent = ele.parentNode;
275      $buttonParent.classList.add("copy-true");
276      const selection = window.getSelection();
277      const range = document.createRange();
278      if (isPrismjs) range.selectNodeContents($buttonParent.querySelectorAll("pre code")[0]);
279      else range.selectNodeContents($buttonParent.querySelectorAll("table .code pre")[0]);
280      selection.removeAllRanges();
281      selection.addRange(range);
282      const text = selection.toString();
283      copy(text, ele.lastChild);
284      selection.removeAllRanges();
285      $buttonParent.classList.remove("copy-true");
286    };
287
288    const highlightShrinkFn = ele => {
289      const $nextEle = [...ele.parentNode.children].slice(1);
290      ele.firstChild.classList.toggle("closed");
291      if (anzhiyu.isHidden($nextEle[$nextEle.length - 1])) {
292        $nextEle.forEach(e => {
293          e.style.display = "block";
294        });
295      } else {
296        $nextEle.forEach(e => {
297          e.style.display = "none";
298        });
299      }
300    };
301
302    const highlightToolsFn = function (e) {
303      const $target = e.target.classList;
304      if ($target.contains("expand")) highlightShrinkFn(this);
305      else if ($target.contains("copy-button")) highlightCopyFn(this);
306    };
307
308    const expandCode = function () {
309      this.classList.toggle("expand-done");
310    };
311
312    const createEle = (lang, item, service) => {
313      const fragment = document.createDocumentFragment();
314
315      if (isShowTool) {
316        const hlTools = document.createElement("div");
317        hlTools.className = `highlight-tools ${highlightShrinkClass}`;
318        hlTools.innerHTML = highlightShrinkEle + lang + highlightCopyEle;
319        anzhiyu.addEventListenerPjax(hlTools, "click", highlightToolsFn);
320        fragment.appendChild(hlTools);
321      }
322
323      if (highlightHeightLimit && item.offsetHeight > highlightHeightLimit + 30) {
324        const ele = document.createElement("div");
325        ele.className = "code-expand-btn";
326        ele.innerHTML = '<i class="anzhiyufont anzhiyu-icon-angle-double-down"></i>';
327        anzhiyu.addEventListenerPjax(ele, "click", expandCode);
328        fragment.appendChild(ele);
329      }
330
331      if (service === "hl") {
332        item.insertBefore(fragment, item.firstChild);
333      } else {
334        item.parentNode.insertBefore(fragment, item);
335      }
336    };
337
338    if (isHighlightLang) {
339      if (isPrismjs) {
340        $figureHighlight.forEach(function (item) {
341          const langName = item.getAttribute("data-language") ? item.getAttribute("data-language") : "Code";
342          const highlightLangEle = `<div class="code-lang">${langName}</div>`;
343          anzhiyu.wrap(item, "figure", { class: "highlight" });
344          createEle(highlightLangEle, item);
345        });
346      } else {
347        $figureHighlight.forEach(function (item) {
348          let langName = item.getAttribute("class").split(" ")[1];
349          if (langName === "plain" || langName === undefined || langName === "plaintext") langName = "Code";
350          const highlightLangEle = `<div class="code-lang">${langName}</div>`;
351          createEle(highlightLangEle, item, "hl");
352        });
353      }
354    } else {
355      if (isPrismjs) {
356        $figureHighlight.forEach(function (item) {
357          anzhiyu.wrap(item, "figure", { class: "highlight" });
358          createEle("", item);
359        });
360      } else {
361        $figureHighlight.forEach(function (item) {
362          createEle("", item, "hl");
363        });
364      }
365    }
366  };
367
368  /**
369   * PhotoFigcaption
370   */
371  function addPhotoFigcaption() {
372    document.querySelectorAll("#article-container img").forEach(function (item) {
373      const parentEle = item.parentNode;
374      const altValue = item.title || item.alt;
375      if (altValue && !parentEle.parentNode.classList.contains("justified-gallery")) {
376        const ele = document.createElement("div");
377        ele.className = "img-alt is-center";
378        ele.textContent = altValue;
379        parentEle.insertBefore(ele, item.nextSibling);
380      }
381    });
382  }
383
384  /**
385   * Lightbox
386   */
387  const runLightbox = () => {
388    anzhiyu.loadLightbox(document.querySelectorAll("#article-container img:not(.no-lightbox)"));
389  };
390
391  /**
392   * justified-gallery 圖庫排版
393   */
394  const runJustifiedGallery = function (ele) {
395    const htmlStr = arr => {
396      let str = "";
397      const replaceDq = str => str.replace(/"/g, "&quot;"); // replace double quotes to &quot;
398      arr.forEach(i => {
399        const alt = i.alt ? `alt="${replaceDq(i.alt)}"` : "";
400        const title = i.title ? `title="${replaceDq(i.title)}"` : "";
401        const address = i.address ? i.address : "";
402        const galleryItem = `
403        <div class="fj-gallery-item">
404          ${address ? `<div class="tag-address">${address}</div>` : ""}
405          <img src="${i.url}" ${alt + title}>
406        </div>
407      `;
408        str += galleryItem;
409      });
410
411      return str;
412    };
413
414    const lazyloadFn = (i, arr, limit) => {
415      const loadItem = Number(limit);
416      const arrLength = arr.length;
417      if (arrLength > loadItem) i.insertAdjacentHTML("beforeend", htmlStr(arr.splice(0, loadItem)));
418      else {
419        i.insertAdjacentHTML("beforeend", htmlStr(arr));
420        i.classList.remove("lazyload");
421      }
422      window.lazyLoadInstance && window.lazyLoadInstance.update();
423      return arrLength > loadItem ? loadItem : arrLength;
424    };
425
426    const fetchUrl = async url => {
427      const response = await fetch(url);
428      return await response.json();
429    };
430
431    const runJustifiedGallery = (item, arr) => {
432      const limit = item.getAttribute("data-limit") ?? arr.length;
433      if (!item.classList.contains("lazyload") || arr.length < limit) {
434        // 不懒加载
435        item.innerHTML = htmlStr(arr);
436        item.nextElementSibling.style.display = "none";
437      } else {
438        if (!item.classList.contains("btn_album_detail_lazyload") || item.classList.contains("page_img_lazyload")) {
439          // 滚动懒加载
440          lazyloadFn(item, arr, limit);
441          const clickBtnFn = () => {
442            const lastItemLength = lazyloadFn(item, arr, limit);
443            fjGallery(
444              item,
445              "appendImages",
446              item.querySelectorAll(`.fj-gallery-item:nth-last-child(-n+${lastItemLength})`)
447            );
448            anzhiyu.loadLightbox(item.querySelectorAll("img"));
449            if (lastItemLength < Number(limit)) {
450              observer.unobserve(item.nextElementSibling);
451            }
452          };
453
454          // 创建IntersectionObserver实例
455          const observer = new IntersectionObserver((entries, observer) => {
456            entries.forEach(entry => {
457              // 如果元素进入视口
458              if (entry.isIntersecting) {
459                // 执行clickBtnFn函数
460                setTimeout(clickBtnFn(), 100);
461              }
462            });
463          });
464          observer.observe(item.nextElementSibling);
465        } else {
466          // 相册详情 按钮懒加载
467          lazyloadFn(item, arr, limit);
468          const clickBtnFn = () => {
469            const lastItemLength = lazyloadFn(item, arr, limit);
470            fjGallery(
471              item,
472              "appendImages",
473              item.querySelectorAll(`.fj-gallery-item:nth-last-child(-n+${lastItemLength})`)
474            );
475            anzhiyu.loadLightbox(item.querySelectorAll("img"));
476            lastItemLength < limit && item.nextElementSibling.removeEventListener("click", clickBtnFn);
477          };
478          item.nextElementSibling.addEventListener("click", clickBtnFn);
479        }
480      }
481
482      anzhiyu.initJustifiedGallery(item);
483      anzhiyu.loadLightbox(item.querySelectorAll("img"));
484      window.lazyLoadInstance && window.lazyLoadInstance.update();
485    };
486
487    const addJustifiedGallery = () => {
488      ele.forEach(item => {
489        item.classList.contains("url")
490          ? fetchUrl(item.textContent).then(res => {
491              runJustifiedGallery(item, res);
492            })
493          : runJustifiedGallery(item, JSON.parse(item.textContent));
494      });
495    };
496
497    if (window.fjGallery) {
498      addJustifiedGallery();
499      return;
500    }
501
502    getCSS(`${GLOBAL_CONFIG.source.justifiedGallery.css}`);
503    getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(addJustifiedGallery);
504  };
505
506  /**
507   * 滚动处理
508   */
509  const scrollFn = function () {
510    const $rightside = document.getElementById("rightside");
511    const innerHeight = window.innerHeight + 56;
512    let lastScrollTop = 0;
513
514    if (document.body.scrollHeight <= innerHeight) {
515      $rightside.style.cssText = "opacity: 1; transform: translateX(-58px)";
516    }
517
518    // find the scroll direction
519    function scrollDirection(currentTop) {
520      const result = currentTop > initTop; // true is down & false is up
521      initTop = currentTop;
522      return result;
523    }
524
525    let initTop = 0;
526    let isChatShow = true;
527    const $header = document.getElementById("page-header");
528    const $popupWindow = document.getElementById("popup-window");
529    const isChatBtnHide = typeof chatBtnHide === "function";
530    const isChatBtnShow = typeof chatBtnShow === "function";
531
532    // 第一次滑动到底部的标识符
533    let scrollBottomFirstFlag = false;
534    // 缓存常用dom元素
535    const musicDom = document.getElementById("nav-music"),
536      footerDom = document.getElementById("footer"),
537      waterfallDom = document.getElementById("waterfall"),
538      $percentBtn = document.getElementById("percent"),
539      $navTotop = document.getElementById("nav-totop"),
540      $bodyWrap = document.getElementById("body-wrap");
541    // 页面底部Dom是否存在
542    let pageBottomDomFlag = document.getElementById("post-comment") || document.getElementById("footer");
543
544    function percentageScrollFn(currentTop) {
545      // 处理滚动百分比
546      let docHeight = $bodyWrap.clientHeight;
547      const winHeight = document.documentElement.clientHeight;
548      const contentMath =
549        docHeight > winHeight ? docHeight - winHeight : document.documentElement.scrollHeight - winHeight;
550      const scrollPercent = currentTop / contentMath;
551      const scrollPercentRounded = Math.round(scrollPercent * 100);
552      const percentage = scrollPercentRounded > 100 ? 100 : scrollPercentRounded <= 0 ? 1 : scrollPercentRounded;
553      $percentBtn.textContent = percentage;
554
555      function isInViewPortOfOneNoDis(el) {
556        if (!el) return;
557        const elDisplay = window.getComputedStyle(el).getPropertyValue("display");
558        if (elDisplay == "none") {
559          return;
560        }
561        const viewPortHeight =
562          window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
563        const offsetTop = el.offsetTop;
564        const scrollTop = document.documentElement.scrollTop;
565        const top = offsetTop - scrollTop;
566        return top <= viewPortHeight;
567      }
568
569      if (isInViewPortOfOneNoDis(pageBottomDomFlag || percentage > 90) && currentTop > 20) {
570        $navTotop.classList.add("long");
571        $percentBtn.textContent = "返回顶部";
572      } else {
573        $navTotop.classList.remove("long");
574        $percentBtn.textContent = percentage;
575      }
576
577      // 如果当前页面需要瀑布流,就处理瀑布流
578      if (waterfallDom) {
579        const waterfallResult = currentTop % document.documentElement.clientHeight; // 卷去一个视口
580        if (!scrollBottomFirstFlag && waterfallResult + 100 >= document.documentElement.clientHeight) {
581          console.info(waterfallResult, document.documentElement.clientHeight);
582          setTimeout(() => {
583            waterfall("#waterfall");
584          }, 500);
585        } else {
586          setTimeout(() => {
587            waterfallDom && waterfall("#waterfall");
588          }, 500);
589        }
590      }
591    }
592
593    const scrollTask = anzhiyu.throttle(() => {
594      const currentTop = window.scrollY || document.documentElement.scrollTop;
595      const isDown = scrollDirection(currentTop);
596
597      const delta = Math.abs(lastScrollTop - currentTop);
598      if (currentTop > 60 && delta < 20 && delta != 0) {
599        // ignore small scrolls
600        return;
601      }
602      if (
603        $popupWindow &&
604        $popupWindow.classList.contains("show-popup-window") &&
605        currentTop > 60 &&
606        delta > 20 &&
607        lastScrollTop != 0
608      ) {
609        // 滚动后延迟1s关闭弹窗
610        anzhiyu.throttle(() => {
611          if (popupWindowTimer) clearTimeout(popupWindowTimer);
612          popupWindowTimer = setTimeout(() => {
613            if (!$popupWindow.classList.contains("popup-hide")) {
614              $popupWindow.classList.add("popup-hide");
615            }
616            setTimeout(() => {
617              $popupWindow.classList.remove("popup-hide");
618              $popupWindow.classList.remove("show-popup-window");
619            }, 1000);
620          }, 1000);
621        }, 1000)();
622      }
623      lastScrollTop = currentTop;
624
625      if (currentTop > 26) {
626        if (isDown) {
627          if ($header.classList.contains("nav-visible")) $header.classList.remove("nav-visible");
628          if (isChatBtnShow && isChatShow === true) {
629            chatBtnHide();
630            isChatShow = false;
631          }
632        } else {
633          if (!$header.classList.contains("nav-visible")) $header.classList.add("nav-visible");
634          if (isChatBtnHide && isChatShow === false) {
635            chatBtnShow();
636            isChatShow = true;
637          }
638        }
639        requestAnimationFrame(() => {
640          anzhiyu.initThemeColor();
641          $header.classList.add("nav-fixed");
642        });
643        if (window.getComputedStyle($rightside).getPropertyValue("opacity") === "0") {
644          $rightside.style.cssText = "opacity: 0.8; transform: translateX(-58px)";
645        }
646      } else {
647        if (currentTop <= 5) {
648          requestAnimationFrame(() => {
649            $header.classList.remove("nav-fixed");
650            $header.classList.remove("nav-visible");
651            // 修改顶栏颜色
652            anzhiyu.initThemeColor();
653          });
654        }
655        $rightside.style.cssText = "opacity: ''; transform: ''";
656      }
657
658      if (document.body.scrollHeight <= innerHeight) {
659        $rightside.style.cssText = "opacity: 0.8; transform: translateX(-58px)";
660      }
661
662      percentageScrollFn(currentTop);
663    }, 96);
664
665    // 进入footer隐藏音乐
666    if (footerDom) {
667      anzhiyu
668        .intersectionObserver(
669          () => {
670            if (footerDom && musicDom && 768 < document.body.clientWidth) {
671              musicDom.style.bottom = "-10px";
672              musicDom.style.opacity = "0";
673            }
674            scrollBottomFirstFlag = true;
675          },
676          () => {
677            if (footerDom && musicDom && 768 < document.body.clientWidth) {
678              musicDom.style.bottom = "20px";
679              musicDom.style.opacity = "1";
680            }
681          }
682        )()
683        .observe(footerDom);
684    }
685
686    scrollTask();
687    anzhiyu.addEventListenerPjax(window, "scroll", scrollTask, { passive: true });
688  };
689
690  /**
691   * toc,anchor
692   */
693  const scrollFnToDo = function () {
694    const isToc = GLOBAL_CONFIG_SITE.isToc;
695    const isAnchor = GLOBAL_CONFIG.isAnchor;
696    const $article = document.getElementById("article-container");
697
698    if (!($article && (isToc || isAnchor))) return;
699
700    let $tocLink, $cardToc, autoScrollToc, isExpand;
701    if (isToc) {
702      const $cardTocLayout = document.getElementById("card-toc");
703      $cardToc = $cardTocLayout.querySelector(".toc-content");
704      $tocLink = $cardToc.querySelectorAll(".toc-link");
705      $tocPercentage = $cardTocLayout.querySelector(".toc-percentage");
706      isExpand = $cardToc.classList.contains("is-expand");
707
708      // toc元素點擊
709      const tocItemClickFn = e => {
710        const target = e.target.closest(".toc-link");
711        if (!target) return;
712
713        e.preventDefault();
714        anzhiyu.scrollToDest(
715          anzhiyu.getEleTop(document.getElementById(decodeURI(target.getAttribute("href")).replace("#", ""))),
716          300
717        );
718        if (window.innerWidth < 900) {
719          $cardTocLayout.classList.remove("open");
720        }
721      };
722
723      anzhiyu.addEventListenerPjax($cardToc, "click", tocItemClickFn);
724
725      autoScrollToc = item => {
726        const activePosition = item.getBoundingClientRect().top;
727        const sidebarScrollTop = $cardToc.scrollTop;
728        if (activePosition > document.documentElement.clientHeight - 100) {
729          $cardToc.scrollTop = sidebarScrollTop + 150;
730        }
731        if (activePosition < 100) {
732          $cardToc.scrollTop = sidebarScrollTop - 150;
733        }
734      };
735    }
736
737    // find head position & add active class
738    const list = $article.querySelectorAll("h1,h2,h3,h4,h5,h6");
739    const filteredHeadings = Array.from(list).filter(heading => heading.id !== "CrawlerTitle");
740    let detectItem = "";
741    const findHeadPosition = function (top) {
742      if (top === 0) {
743        return false;
744      }
745
746      let currentId = "";
747      let currentIndex = "";
748
749      filteredHeadings.forEach(function (ele, index) {
750        if (top > anzhiyu.getEleTop(ele) - 80) {
751          const id = ele.id;
752          currentId = id ? "#" + encodeURI(id) : "";
753          currentIndex = index;
754        }
755      });
756      if (detectItem === currentIndex) return;
757      if (isAnchor) anzhiyu.updateAnchor(currentId);
758      detectItem = currentIndex;
759      if (isToc) {
760        $cardToc.querySelectorAll(".active").forEach(i => {
761          i.classList.remove("active");
762        });
763
764        if (currentId === "") {
765          return;
766        }
767        const currentActive = $tocLink[currentIndex];
768        currentActive.classList.add("active");
769
770        setTimeout(() => {
771          autoScrollToc(currentActive);
772        }, 0);
773
774        if (isExpand) return;
775        let parent = currentActive.parentNode;
776
777        for (; !parent.matches(".toc"); parent = parent.parentNode) {
778          if (parent.matches("li")) parent.classList.add("active");
779        }
780      }
781    };
782
783    // main of scroll
784    const tocScrollFn = anzhiyu.throttle(() => {
785      const currentTop = window.scrollY || document.documentElement.scrollTop;
786      findHeadPosition(currentTop);
787    }, 100);
788
789    anzhiyu.addEventListenerPjax(window, "scroll", tocScrollFn, { passive: true });
790  };
791
792  const handleThemeChange = mode => {
793    const globalFn = window.globalFn || {};
794    const themeChange = globalFn.themeChange || {};
795    if (!themeChange) {
796      return;
797    }
798
799    Object.keys(themeChange).forEach(key => {
800      const themeChangeFn = themeChange[key];
801      themeChangeFn(mode);
802    });
803
804    rm && rm.hideRightMenu();
805
806    const menuDarkmodeText = $rightMenu.querySelector(".menu-darkmode-text");
807    if (mode === "light") {
808      menuDarkmodeText.textContent = "深色模式";
809    } else {
810      menuDarkmodeText.textContent = "浅色模式";
811    }
812
813    if (!GLOBAL_CONFIG_SITE.isPost) {
814      const root = document.querySelector(":root");
815      root.style.setProperty("--anzhiyu-bar-background", "var(--anzhiyu-meta-theme-color)");
816      requestAnimationFrame(() => {
817        anzhiyu.initThemeColor();
818      });
819
820      // 要改回来默认主色;
821      document.documentElement.style.setProperty(
822        "--anzhiyu-main",
823        getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-theme")
824      );
825      document.documentElement.style.setProperty(
826        "--anzhiyu-theme-op",
827        getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "23"
828      );
829      document.documentElement.style.setProperty(
830        "--anzhiyu-theme-op-deep",
831        getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "dd"
832      );
833    }
834  };
835
836  /**
837   * Rightside
838   */
839  const rightSideFn = {
840    readmode: () => {
841      // read mode
842      const $body = document.body;
843      $body.classList.add("read-mode");
844      const newEle = document.createElement("button");
845      newEle.type = "button";
846      newEle.className = "anzhiyufont anzhiyu-icon-xmark exit-readmode";
847      $body.appendChild(newEle);
848
849      const clickFn = () => {
850        $body.classList.remove("read-mode");
851        newEle.remove();
852        newEle.removeEventListener("click", clickFn);
853      };
854
855      newEle.addEventListener("click", clickFn);
856    },
857    darkmode: () => {
858      // switch between light and dark mode
859      const willChangeMode = document.documentElement.getAttribute("data-theme") === "dark" ? "light" : "dark";
860      if (willChangeMode === "dark") {
861        activateDarkMode();
862        GLOBAL_CONFIG.Snackbar !== undefined && anzhiyu.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night);
863      } else {
864        activateLightMode();
865        GLOBAL_CONFIG.Snackbar !== undefined && anzhiyu.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day);
866      }
867      saveToLocal.set("theme", willChangeMode, 2);
868      handleThemeChange(willChangeMode);
869    },
870    "rightside-config": item => {
871      // Show or hide rightside-hide-btn
872      const hideLayout = item.firstElementChild;
873      if (hideLayout.classList.contains("show")) {
874        hideLayout.classList.add("status");
875        setTimeout(() => {
876          hideLayout.classList.remove("status");
877        }, 300);
878      }
879
880      hideLayout.classList.toggle("show");
881    },
882    "go-up": () => {
883      // Back to top
884      anzhiyu.scrollToDest(0, 500);
885    },
886    "hide-aside-btn": () => {
887      // Hide aside
888      const $htmlDom = document.documentElement.classList;
889      const saveStatus = $htmlDom.contains("hide-aside") ? "show" : "hide";
890      saveToLocal.set("aside-status", saveStatus, 2);
891      $htmlDom.toggle("hide-aside");
892    },
893    "mobile-toc-button": item => {
894      // Show mobile toc
895      const tocEle = document.getElementById("card-toc");
896      tocEle.style.transformOrigin = `right ${item.getBoundingClientRect().top + 17}px`;
897      tocEle.style.transition = "transform 0.3s ease-in-out";
898      tocEle.classList.toggle("open");
899      tocEle.addEventListener(
900        "transitionend",
901        () => {
902          tocEle.style.transition = "";
903          tocEle.style.transformOrigin = "";
904        },
905        { once: true }
906      );
907    },
908    "chat-btn": () => {
909      // Show chat
910      window.chatBtnFn();
911    },
912    translateLink: () => {
913      // switch between traditional and simplified chinese
914      window.translateFn.translatePage();
915    },
916  };
917
918  document.getElementById("rightside").addEventListener("click", function (e) {
919    const $target = e.target.closest("[id]");
920    if ($target && rightSideFn[$target.id]) {
921      rightSideFn[$target.id](this);
922    }
923  });
924
925  //监听蒙版关闭
926  document.addEventListener(
927    "touchstart",
928    e => {
929      anzhiyu.removeRewardMask();
930    },
931    { passive: true }
932  );
933
934  /**
935   * menu
936   * 側邊欄sub-menu 展開/收縮
937   */
938  const clickFnOfSubMenu = () => {
939    const handleClickOfSubMenu = e => {
940      const target = e.target.closest(".site-page.group");
941      if (!target) return;
942      target.classList.toggle("hide");
943    };
944
945    document.querySelector("#sidebar-menus .menus_items") &&
946      document.querySelector("#sidebar-menus .menus_items").addEventListener("click", handleClickOfSubMenu);
947  };
948
949  /**
950   * 手机端目录点击
951   */
952  const openMobileMenu = () => {
953    const handleClick = () => {
954      sidebarFn.open();
955    };
956    anzhiyu.addEventListenerPjax(document.getElementById("toggle-menu"), "click", handleClick);
957  };
958
959  /**
960   * 複製時加上版權信息
961   */
962  const addCopyright = () => {
963    const { limitCount, languages, copy, copyrightEbable } = GLOBAL_CONFIG.copyright;
964
965    const handleCopy = e => {
966      if (copy) {
967        anzhiyu.snackbarShow(languages.copySuccess);
968      }
969      if (copyrightEbable) {
970        e.preventDefault();
971        const copyFont = window.getSelection(0).toString();
972        let textFont = copyFont;
973        if (copyFont.length > limitCount) {
974          textFont = `${copyFont}\n\n\n${languages.author}\n${languages.link}${window.location.href}\n${languages.source}\n${languages.info}`;
975        }
976        if (e.clipboardData) {
977          return e.clipboardData.setData("text", textFont);
978        } else {
979          return window.clipboardData.setData("text", textFont);
980        }
981      }
982    };
983
984    document.body.addEventListener("copy", handleCopy);
985  };
986
987  /**
988   * 網頁運行時間
989   */
990  const addRuntime = () => {
991    const $runtimeCount = document.getElementById("runtimeshow");
992    if ($runtimeCount) {
993      const publishDate = $runtimeCount.getAttribute("data-publishDate");
994      $runtimeCount.textContent = `${anzhiyu.diffDate(publishDate)} ${GLOBAL_CONFIG.runtime}`;
995    }
996  };
997
998  /**
999   * 最後一次更新時間
1000   */
1001  const addLastPushDate = () => {
1002    const $lastPushDateItem = document.getElementById("last-push-date");
1003    if ($lastPushDateItem) {
1004      const lastPushDate = $lastPushDateItem.getAttribute("data-lastPushDate");
1005      $lastPushDateItem.textContent = anzhiyu.diffDate(lastPushDate, true);
1006    }
1007  };
1008
1009  /**
1010   * table overflow
1011   */
1012  const addTableWrap = () => {
1013    const $table = document.querySelectorAll("#article-container table");
1014    if (!$table.length) return;
1015
1016    $table.forEach(item => {
1017      if (!item.closest(".highlight")) {
1018        anzhiyu.wrap(item, "div", { class: "table-wrap" });
1019      }
1020    });
1021  };
1022
1023  /**
1024   * tag-hide
1025   */
1026  const clickFnOfTagHide = () => {
1027    const hideButtons = document.querySelectorAll("#article-container .hide-button");
1028    if (!hideButtons.length) return;
1029    const handleClick = function (e) {
1030      const $this = this;
1031      $this.classList.add("open");
1032      const $fjGallery = $this.nextElementSibling.querySelectorAll(".gallery-container");
1033      $fjGallery.length && addJustifiedGallery($fjGallery);
1034    };
1035
1036    hideButtons.forEach(item => {
1037      item.addEventListener("click", handleClick, { once: true });
1038    });
1039  };
1040
1041  const tabsFn = () => {
1042    const navTabsElement = document.querySelectorAll("#article-container .tabs");
1043    if (!navTabsElement.length) return;
1044
1045    const removeAndAddActiveClass = (elements, detect) => {
1046      Array.from(elements).forEach(element => {
1047        element.classList.remove("active");
1048        if (element === detect || element.id === detect) {
1049          element.classList.add("active");
1050        }
1051      });
1052    };
1053
1054    const addTabNavEventListener = (item, isJustifiedGallery) => {
1055      const navClickHandler = function (e) {
1056        const target = e.target.closest("button");
1057        if (target.classList.contains("active")) return;
1058        removeAndAddActiveClass(this.children, target);
1059        this.classList.remove("no-default");
1060        const tabId = target.getAttribute("data-href");
1061        const tabContent = this.nextElementSibling;
1062        removeAndAddActiveClass(tabContent.children, tabId);
1063        if (isJustifiedGallery) {
1064          const $isTabJustifiedGallery = tabContent.querySelectorAll(`#${tabId} .fj-gallery`);
1065          if ($isTabJustifiedGallery.length > 0) {
1066            anzhiyu.initJustifiedGallery($isTabJustifiedGallery);
1067          }
1068        }
1069      };
1070      anzhiyu.addEventListenerPjax(item.firstElementChild, "click", navClickHandler);
1071    };
1072
1073    const addTabToTopEventListener = item => {
1074      const btnClickHandler = e => {
1075        const target = e.target.closest("button");
1076        if (!target) return;
1077        anzhiyu.scrollToDest(anzhiyu.getEleTop(item), 300);
1078      };
1079      anzhiyu.addEventListenerPjax(item.lastElementChild, "click", btnClickHandler);
1080    };
1081
1082    navTabsElement.forEach(item => {
1083      const isJustifiedGallery = !!item.querySelectorAll(".gallery-container");
1084      addTabNavEventListener(item, isJustifiedGallery);
1085      addTabToTopEventListener(item);
1086    });
1087  };
1088
1089  const toggleCardCategory = () => {
1090    const cardCategory = document.querySelector("#aside-cat-list.expandBtn");
1091    if (!cardCategory) return;
1092
1093    const handleToggleBtn = e => {
1094      const target = e.target;
1095      if (target.nodeName === "I") {
1096        e.preventDefault();
1097        target.parentNode.classList.toggle("expand");
1098      }
1099    };
1100    anzhiyu.addEventListenerPjax(cardCategory, "click", handleToggleBtn, true);
1101  };
1102
1103  const switchComments = () => {
1104    const switchBtn = document.getElementById("switch-btn");
1105    if (!switchBtn) return;
1106    let switchDone = false;
1107    const commentContainer = document.getElementById("post-comment");
1108    const handleSwitchBtn = () => {
1109      commentContainer.classList.toggle("move");
1110      if (!switchDone) {
1111        switchDone = true;
1112        loadOtherComment();
1113      }
1114    };
1115    anzhiyu.addEventListenerPjax(switchBtn, "click", handleSwitchBtn);
1116  };
1117
1118  const addPostOutdateNotice = function () {
1119    const data = GLOBAL_CONFIG.noticeOutdate;
1120    const diffDay = anzhiyu.diffDate(GLOBAL_CONFIG_SITE.postUpdate);
1121    if (diffDay >= data.limitDay) {
1122      const ele = document.createElement("div");
1123      ele.className = "post-outdate-notice";
1124      ele.textContent = data.messagePrev + " " + diffDay + " " + data.messageNext;
1125      const $targetEle = document.getElementById("article-container");
1126      if (data.position === "top") {
1127        $targetEle.insertBefore(ele, $targetEle.firstChild);
1128      } else {
1129        $targetEle.appendChild(ele);
1130      }
1131    }
1132  };
1133
1134  const lazyloadImg = () => {
1135    window.lazyLoadInstance = new LazyLoad({
1136      elements_selector: "img",
1137      threshold: 0,
1138      data_src: "lazy-src",
1139    });
1140  };
1141
1142  const relativeDate = function (selector) {
1143    selector.forEach(item => {
1144      const timeVal = item.getAttribute("datetime");
1145      item.textContent = anzhiyu.diffDate(timeVal, true);
1146      item.style.display = "inline";
1147    });
1148  };
1149
1150  const mouseleaveHomeCard = function () {
1151    const topGroup = document.querySelector(".topGroup");
1152    if (!topGroup) return;
1153    //首页大卡片恢复显示
1154    topGroup.addEventListener("mouseleave", function () {
1155      document.getElementById("todayCard").classList.remove("hide");
1156      document.getElementById("todayCard").style.zIndex = 1;
1157    });
1158  };
1159
1160  // 表情放大
1161  const owoBig = function () {
1162    let flag = 1, // 设置节流阀
1163      owo_time = "", // 设置计时器
1164      m = 3; // 设置放大倍数
1165    // 创建盒子
1166    let div = document.createElement("div");
1167    // 设置ID
1168    div.id = "owo-big";
1169    // 插入盒子
1170    let body = document.querySelector("body");
1171    body.appendChild(div);
1172
1173    // 监听 post-comment 元素的子元素添加事件
1174    const observer = new MutationObserver(mutations => {
1175      mutations.forEach(mutation => {
1176        const addedNodes = mutation.addedNodes;
1177        // 判断新增的节点中是否包含 OwO-body 类名的元素
1178        for (let i = 0; i < addedNodes.length; i++) {
1179          const node = addedNodes[i];
1180          if (
1181            node.nodeType === Node.ELEMENT_NODE &&
1182            node.classList.contains("OwO-body") &&
1183            !node.classList.contains("comment-barrage")
1184          ) {
1185            const owo_body = node;
1186            // 禁用右键(手机端长按会出现右键菜单,为了体验给禁用掉)
1187            owo_body.addEventListener("contextmenu", e => e.preventDefault());
1188            // 鼠标移入
1189            owo_body.addEventListener("mouseover", handleMouseOver);
1190            // 鼠标移出
1191            owo_body.addEventListener("mouseout", handleMouseOut);
1192          }
1193        }
1194      });
1195    });
1196
1197    // 配置 MutationObserver 选项
1198    const config = { childList: true, subtree: true };
1199
1200    // 开始监听
1201    observer.observe(document.getElementById("post-comment"), config);
1202
1203    function handleMouseOver(e) {
1204      if (e.target.tagName == "IMG" && flag) {
1205        flag = 0;
1206        // 移入100毫秒后显示盒子
1207        owo_time = setTimeout(() => {
1208          let height = e.target.clientHeight * m; // 盒子高
1209          let width = e.target.clientWidth * m; // 盒子宽
1210          let left = e.x - e.offsetX - (width - e.target.clientWidth) / 2; // 盒子与屏幕左边距离
1211          if (left + width > body.clientWidth) {
1212            left -= left + width - body.clientWidth + 10;
1213          } // 右边缘检测,防止超出屏幕
1214          if (left < 0) left = 10; // 左边缘检测,防止超出屏幕
1215          let top = e.y - e.offsetY; // 盒子与屏幕顶部距离
1216
1217          // 设置盒子样式
1218          div.style.height = height + "px";
1219          div.style.width = width + "px";
1220          div.style.left = left + "px";
1221          div.style.top = top + "px";
1222          div.style.display = "flex";
1223          // 在盒子中插入图片
1224          div.innerHTML = `<img src="${e.target.src}">`;
1225        }, 100);
1226      }
1227    }
1228
1229    function handleMouseOut(e) {
1230      // 隐藏盒子
1231      div.style.display = "none";
1232      flag = 1;
1233      clearTimeout(owo_time);
1234    }
1235  };
1236
1237  //封面纯色
1238  const coverColor = async () => {
1239    const root = document.querySelector(":root");
1240    const path = document.getElementById("post-top-bg")?.src;
1241    if (!path) {
1242      // 非文章情况,直接设置不需要请求了
1243      root.style.setProperty("--anzhiyu-bar-background", "var(--anzhiyu-meta-theme-color)");
1244      requestAnimationFrame(() => {
1245        anzhiyu.initThemeColor();
1246      });
1247
1248      // 要改回来默认主色
1249      document.documentElement.style.setProperty(
1250        "--anzhiyu-main",
1251        getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-theme")
1252      );
1253      document.documentElement.style.setProperty(
1254        "--anzhiyu-theme-op",
1255        getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "23"
1256      );
1257      document.documentElement.style.setProperty(
1258        "--anzhiyu-theme-op-deep",
1259        getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "dd"
1260      );
1261
1262      return;
1263    }
1264
1265    // 文章内
1266    if (GLOBAL_CONFIG.mainTone) {
1267      if (GLOBAL_CONFIG_SITE.postMainColor) {
1268        let value = GLOBAL_CONFIG_SITE.postMainColor;
1269        if (getContrastYIQ(value) === "light") {
1270          value = LightenDarkenColor(colorHex(value), -40);
1271        }
1272
1273        root.style.setProperty("--anzhiyu-bar-background", value);
1274        requestAnimationFrame(() => {
1275          anzhiyu.initThemeColor();
1276        });
1277
1278        if (GLOBAL_CONFIG.mainTone.cover_change) {
1279          document.documentElement.style.setProperty("--anzhiyu-main", value);
1280          document.documentElement.style.setProperty(
1281            "--anzhiyu-theme-op",
1282            getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "23"
1283          );
1284          document.documentElement.style.setProperty(
1285            "--anzhiyu-theme-op-deep",
1286            getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "dd"
1287          );
1288        }
1289      } else {
1290        const fallbackValue = "var(--anzhiyu-theme)";
1291        let fetchPath = "";
1292        if (GLOBAL_CONFIG.mainTone.mode == "cdn" || GLOBAL_CONFIG.mainTone.mode == "both") {
1293          fetchPath = path + "?imageAve";
1294        } else if (GLOBAL_CONFIG.mainTone.mode == "api") {
1295          fetchPath = GLOBAL_CONFIG.mainTone.api + path;
1296        }
1297        // cdn/api模式请求
1298        try {
1299          const response = await fetch(fetchPath);
1300          if (response.ok && response.headers.get("content-type")?.includes("application/json")) {
1301            const obj = await response.json();
1302            let value =
1303              GLOBAL_CONFIG.mainTone.mode == "cdn" || GLOBAL_CONFIG.mainTone.mode == "both"
1304                ? "#" + obj.RGB.slice(2)
1305                : obj.RGB;
1306            if (getContrastYIQ(value) === "light") {
1307              value = LightenDarkenColor(colorHex(value), -40);
1308            }
1309
1310            root.style.setProperty("--anzhiyu-bar-background", value);
1311            requestAnimationFrame(() => {
1312              anzhiyu.initThemeColor();
1313            });
1314
1315            if (GLOBAL_CONFIG.mainTone.cover_change) {
1316              document.documentElement.style.setProperty("--anzhiyu-main", value);
1317              document.documentElement.style.setProperty(
1318                "--anzhiyu-theme-op",
1319                getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "23"
1320              );
1321              document.documentElement.style.setProperty(
1322                "--anzhiyu-theme-op-deep",
1323                getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "dd"
1324              );
1325            }
1326          } else {
1327            if (GLOBAL_CONFIG.mainTone.mode == "both") {
1328              // both继续请求
1329              try {
1330                const response = await fetch(GLOBAL_CONFIG.mainTone.api + path);
1331                if (response.ok && response.headers.get("content-type")?.includes("application/json")) {
1332                  const obj = await response.json();
1333                  let value = obj.RGB;
1334
1335                  if (getContrastYIQ(value) === "light") {
1336                    value = LightenDarkenColor(colorHex(value), -40);
1337                  }
1338
1339                  root.style.setProperty("--anzhiyu-bar-background", value);
1340                  requestAnimationFrame(() => {
1341                    anzhiyu.initThemeColor();
1342                  });
1343
1344                  if (GLOBAL_CONFIG.mainTone.cover_change) {
1345                    document.documentElement.style.setProperty("--anzhiyu-main", value);
1346                    document.documentElement.style.setProperty(
1347                      "--anzhiyu-theme-op",
1348                      getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "23"
1349                    );
1350                    document.documentElement.style.setProperty(
1351                      "--anzhiyu-theme-op-deep",
1352                      getComputedStyle(document.documentElement).getPropertyValue("--anzhiyu-main") + "dd"
1353                    );
1354                  }
1355                } else {
1356                  root.style.setProperty("--anzhiyu-bar-background", fallbackValue);
1357                  requestAnimationFrame(() => {
1358                    anzhiyu.initThemeColor();
1359                  });
1360                  document.documentElement.style.setProperty("--anzhiyu-main", fallbackValue);
1361                }
1362              } catch {
1363                root.style.setProperty("--anzhiyu-bar-background", fallbackValue);
1364                requestAnimationFrame(() => {
1365                  anzhiyu.initThemeColor();
1366                });
1367                document.documentElement.style.setProperty("--anzhiyu-main", fallbackValue);
1368              }
1369            } else {
1370              root.style.setProperty("--anzhiyu-bar-background", fallbackValue);
1371              requestAnimationFrame(() => {
1372                anzhiyu.initThemeColor();
1373              });
1374              document.documentElement.style.setProperty("--anzhiyu-main", fallbackValue);
1375            }
1376          }
1377        } catch (err) {
1378          console.error("Error fetching data:", err);
1379          root.style.setProperty("--anzhiyu-bar-background", fallbackValue);
1380          requestAnimationFrame(() => {
1381            anzhiyu.initThemeColor();
1382          });
1383          document.documentElement.style.setProperty("--anzhiyu-main", fallbackValue);
1384        }
1385      }
1386    }
1387  };
1388
1389  //RGB颜色转化为16进制颜色
1390  const colorHex = str => {
1391    const hexRegex = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
1392
1393    if (/^(rgb|RGB)/.test(str)) {
1394      const aColor = str.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
1395      return aColor.reduce((acc, val) => {
1396        const hex = Number(val).toString(16).padStart(2, "0");
1397        return acc + hex;
1398      }, "#");
1399    }
1400
1401    if (hexRegex.test(str)) {
1402      if (str.length === 4) {
1403        return Array.from(str.slice(1)).reduce((acc, val) => acc + val + val, "#");
1404      }
1405      return str;
1406    }
1407
1408    return str;
1409  };
1410
1411  // Lighten or darken a color
1412  const LightenDarkenColor = (col, amt) => {
1413    const usePound = col.startsWith("#");
1414
1415    if (usePound) {
1416      col = col.slice(1);
1417    }
1418
1419    let num = parseInt(col, 16);
1420
1421    const processColor = (colorValue, amount) => {
1422      colorValue += amount;
1423      return colorValue > 255 ? 255 : colorValue < 0 ? 0 : colorValue;
1424    };
1425
1426    const r = processColor(num >> 16, amt);
1427    const b = processColor((num >> 8) & 0x00ff, amt);
1428    const g = processColor(num & 0x0000ff, amt);
1429
1430    return (usePound ? "#" : "") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6);
1431  };
1432
1433  // Determine whether a color is light or dark
1434  const getContrastYIQ = hexcolor => {
1435    const colorRgb = color => {
1436      const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
1437      color = color.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
1438
1439      const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
1440      return result ? `rgb(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)})` : null;
1441    };
1442
1443    const colorrgb = colorRgb(hexcolor);
1444    const colors = colorrgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
1445
1446    const [_, red, green, blue] = colors;
1447
1448    const brightness = (red * 299 + green * 587 + blue * 114) / 255000;
1449
1450    return brightness >= 0.5 ? "light" : "dark";
1451  };
1452
1453  //监听跳转页面输入框是否按下回车
1454  const listenToPageInputPress = function () {
1455    var input = document.getElementById("toPageText");
1456    if (input) {
1457      input.addEventListener("keydown", event => {
1458        if (event.keyCode === 13) {
1459          // 如果按下的是回车键,则执行特定的函数
1460          anzhiyu.toPage();
1461          var link = document.getElementById("toPageButton");
1462          var href = link.href;
1463          pjax.loadUrl(href);
1464        }
1465      });
1466    }
1467  };
1468
1469  // 监听nav是否被其他音频暂停⏸️
1470  const listenNavMusicPause = function () {
1471    const timer = setInterval(() => {
1472      if (navMusicEl && navMusicEl.querySelector("#nav-music meting-js").aplayer) {
1473        clearInterval(timer);
1474        let msgPlay = '<i class="anzhiyufont anzhiyu-icon-play"></i><span>播放音乐</span>';
1475        let msgPause = '<i class="anzhiyufont anzhiyu-icon-pause"></i><span>暂停音乐</span>';
1476        navMusicEl.querySelector("#nav-music meting-js").aplayer.on("pause", function () {
1477          navMusicEl.classList.remove("playing");
1478          document.getElementById("menu-music-toggle").innerHTML = msgPlay;
1479          document.getElementById("nav-music-hoverTips").innerHTML = "音乐已暂停";
1480          document.querySelector("#consoleMusic").classList.remove("on");
1481          anzhiyu_musicPlaying = false;
1482          navMusicEl.classList.remove("stretch");
1483        });
1484        navMusicEl.querySelector("#nav-music meting-js").aplayer.on("play", function () {
1485          navMusicEl.classList.add("playing");
1486          document.getElementById("menu-music-toggle").innerHTML = msgPause;
1487          document.querySelector("#consoleMusic").classList.add("on");
1488          anzhiyu_musicPlaying = true;
1489          // navMusicEl.classList.add("stretch");
1490        });
1491      }
1492    }, 16);
1493  };
1494
1495  // 开发者工具键盘监听
1496  window.onkeydown = function (e) {
1497    123 === e.keyCode && anzhiyu.snackbarShow("开发者模式已打开,请遵循GPL协议", !1);
1498  };
1499
1500  // 欢迎语
1501  function greetingInit() {
1502    const greetingBoxInfo = GLOBAL_CONFIG.greetingBox.list;
1503    const greetingBoxDefault = GLOBAL_CONFIG.greetingBox.default;
1504    //- 创建盒子
1505    let div = document.createElement("div");
1506    //- 设置ID
1507    div.id = "greeting";
1508    //- 设置class
1509    setTimeout(() => {
1510      div.classList.add("shown");
1511    }, 1000);
1512    //- 插入盒子
1513    let greetingBox = document.getElementById("greetingBox");
1514    if (!greetingBox) return;
1515    greetingBox.appendChild(div);
1516    const nowTime = new Date().getHours();
1517    let greetings = greetingBoxDefault;
1518    for (let i = 0; i < greetingBoxInfo.length; i++) {
1519      if (nowTime >= greetingBoxInfo[i].startTime && nowTime <= greetingBoxInfo[i].endTime) {
1520        greetings = greetingBoxInfo[i].greeting;
1521        break;
1522      }
1523    }
1524    div.innerHTML = greetings;
1525    setTimeout(() => {
1526      div.classList.remove("shown");
1527      setTimeout(() => {
1528        greetingBox.remove();
1529      }, 500);
1530    }, 3000);
1531  }
1532  function statistics51aInit() {
1533    const loadScript = (url, charset = "UTF-8", crossorigin, id) => {
1534      return new Promise((resolve, reject) => {
1535        const script = document.createElement("script");
1536        script.src = url;
1537        script.async = true;
1538        if (id) {
1539          script.setAttribute("id", id);
1540        }
1541        if (charset) {
1542          script.setAttribute("charset", charset);
1543        }
1544        if (crossorigin) {
1545          script.setAttribute("crossorigin", crossorigin);
1546        }
1547        script.onerror = reject;
1548        script.onload = script.onreadystatechange = function () {
1549          const loadState = this.readyState;
1550          if (loadState && loadState !== "loaded" && loadState !== "complete") return;
1551          script.onload = script.onreadystatechange = null;
1552          resolve();
1553        };
1554        document.head.appendChild(script);
1555      });
1556    };
1557
1558    const scriptUrls = [
1559      { url: "https://sdk.51.la/js-sdk-pro.min.js", charset: "UTF-8", crossorigin: false, id: "LA_COLLECT" },
1560      { url: "https://sdk.51.la/perf/js-sdk-perf.min.js", crossorigin: "anonymous" },
1561    ];
1562
1563    Promise.all(scriptUrls.map(({ url, charset, crossorigin, id }) => loadScript(url, charset, crossorigin, id)))
1564      .then(() => {
1565        LA.init({ id: GLOBAL_CONFIG.LA51.ck, ck: GLOBAL_CONFIG.LA51.ck });
1566        new LingQue.Monitor().init({ id: GLOBAL_CONFIG.LA51.LingQueMonitorID, sendSuspicious: true });
1567      })
1568      .catch(error => {
1569        console.error("加载51a统计异常,本地加载403是正常情况:", error);
1570      });
1571  }
1572
1573  function setInputFocusListener() {
1574    const inputs = document.querySelectorAll("input, textarea");
1575    const filteredinputs = Array.from(inputs).filter(heading => {
1576      if (heading.id !== "center-console" || heading.id !== "page-type") {
1577        return;
1578      }
1579    });
1580    filteredinputs.forEach(input => {
1581      input.addEventListener("focus", () => {
1582        anzhiyu_intype = true;
1583      });
1584
1585      input.addEventListener("blur", () => {
1586        anzhiyu_intype = false;
1587      });
1588    });
1589  }
1590
1591  // 是否开启快捷键
1592  function executeShortcutKeyFunction() {
1593    // 是否开启快捷键
1594    anzhiyu_keyboard = localStorage.getItem("keyboardToggle") ? localStorage.getItem("keyboardToggle") : false;
1595    function addKeyShotListener() {
1596      const windowObject = window;
1597      windowObject.removeEventListener("keydown", keyDownEvent);
1598      windowObject.removeEventListener("keyup", keyUpEvent);
1599      windowObject.addEventListener("keydown", keyDownEvent);
1600      windowObject.addEventListener("keyup", keyUpEvent);
1601    }
1602
1603    function keyDownEvent(event) {
1604      const isEscapeKeyPressed = event.keyCode === 27;
1605      const isShiftKeyPressed = event.shiftKey;
1606      const isKeyboardEnabled = anzhiyu_keyboard;
1607      const isInInputField = anzhiyu_intype;
1608
1609      if (isEscapeKeyPressed) {
1610        anzhiyu.hideLoading();
1611        anzhiyu.hideConsole();
1612        rm.hideRightMenu();
1613      }
1614      const shortcutKeyDelay = GLOBAL_CONFIG.shortcutKey.delay ? GLOBAL_CONFIG.shortcutKey.delay : 100;
1615      const shortcutKeyShiftDelay = GLOBAL_CONFIG.shortcutKey.shiftDelay ? GLOBAL_CONFIG.shortcutKey.shiftDelay : 200;
1616      if (isKeyboardEnabled && isShiftKeyPressed && !isInInputField) {
1617        anzhiyu_keyUpShiftDelayEvent_timeoutId = setTimeout(() => {
1618          switch (event.keyCode) {
1619            case 16:
1620              anzhiyu_keyUpEvent_timeoutId = setTimeout(() => {
1621                document.querySelector("#keyboard-tips").classList.add("show");
1622              }, shortcutKeyShiftDelay);
1623              break;
1624            case 65:
1625              anzhiyu.switchConsole();
1626              break;
1627            case 77:
1628              anzhiyu.musicToggle();
1629              break;
1630            case 75:
1631              anzhiyu.keyboardToggle();
1632              break;
1633            case 73:
1634              anzhiyu.rightMenuToggle();
1635              break;
1636            case 82:
1637              toRandomPost();
1638              break;
1639            case 72:
1640              pjax.loadUrl("/");
1641              break;
1642            case 68:
1643              rightSideFn.darkmode();
1644              break;
1645            case 70:
1646              pjax.loadUrl("/fcircle/");
1647              break;
1648            case 76:
1649              pjax.loadUrl("/link/");
1650              break;
1651            case 80:
1652              pjax.loadUrl("/about/");
1653              break;
1654            default:
1655              break;
1656          }
1657          event.preventDefault();
1658        }, shortcutKeyDelay);
1659      }
1660    }
1661
1662    window.onfocus = function () {
1663      document.getElementById("keyboard-tips").classList.remove("show");
1664    };
1665
1666    function keyUpEvent(event) {
1667      anzhiyu_keyUpEvent_timeoutId && clearTimeout(anzhiyu_keyUpEvent_timeoutId);
1668      anzhiyu_keyUpShiftDelayEvent_timeoutId && clearTimeout(anzhiyu_keyUpShiftDelayEvent_timeoutId);
1669      if (event.keyCode === 16) {
1670        const keyboardTips = document.querySelector("#keyboard-tips");
1671        keyboardTips.classList.remove("show");
1672      }
1673    }
1674
1675    addKeyShotListener();
1676  }
1677
1678  function changeDocumentTitle() {
1679    let leaveTitle = GLOBAL_CONFIG.diytitle.leaveTitle;
1680    let backTitle = GLOBAL_CONFIG.diytitle.backTitle;
1681    let OriginTitile = document.title;
1682    let titleTime;
1683
1684    document.addEventListener("visibilitychange", function () {
1685      if (document.hidden) {
1686        //离开当前页面时标签显示内容
1687        document.title = leaveTitle;
1688        clearTimeout(titleTime);
1689      } else {
1690        //返回当前页面时标签显示内容
1691        document.title = backTitle + OriginTitile;
1692        //两秒后变回正常标题
1693        titleTime = setTimeout(function () {
1694          document.title = OriginTitile;
1695        }, 2000);
1696      }
1697    });
1698  }
1699
1700  function addDarkModeEventListener(elementId, childSelector) {
1701    const element = document.getElementById(elementId);
1702    if (element && childSelector) {
1703      const childElement = element.querySelector(childSelector);
1704      childElement && childElement.addEventListener("click", rightSideFn.darkmode);
1705    } else if (element) {
1706      element.addEventListener("click", rightSideFn.darkmode);
1707    }
1708  }
1709
1710  const unRefreshFn = function () {
1711    window.addEventListener("resize", () => {
1712      adjustMenu(false);
1713      mobileSidebarOpen && anzhiyu.isHidden(document.getElementById("toggle-menu")) && sidebarFn.close();
1714    });
1715
1716    document.getElementById("menu-mask").addEventListener("click", e => {
1717      sidebarFn.close();
1718    });
1719
1720    // 处理右键
1721    $rightMenu = document.getElementById("rightMenu");
1722    addDarkModeEventListener("menu-darkmode");
1723    addDarkModeEventListener("sidebar", ".darkmode_switchbutton");
1724
1725    clickFnOfSubMenu();
1726    GLOBAL_CONFIG.islazyload && lazyloadImg();
1727    GLOBAL_CONFIG.copyright !== undefined && addCopyright();
1728    GLOBAL_CONFIG.navMusic && listenNavMusicPause();
1729    if (GLOBAL_CONFIG.shortcutKey && document.getElementById("consoleKeyboard")) {
1730      localStorage.setItem("keyboardToggle", "true");
1731      document.getElementById("consoleKeyboard").classList.add("on");
1732      anzhiyu_keyboard = true;
1733      executeShortcutKeyFunction();
1734    }
1735    if (GLOBAL_CONFIG.autoDarkmode) {
1736      window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", e => {
1737        if (saveToLocal.get("theme") !== undefined) return;
1738        e.matches ? handleThemeChange("dark") : handleThemeChange("light");
1739      });
1740    }
1741    // 欢迎语
1742    GLOBAL_CONFIG.greetingBox && greetingInit();
1743    // 51la统计&灵雀统计
1744    GLOBAL_CONFIG.LA51 && statistics51aInit();
1745  };
1746
1747  window.refreshFn = function () {
1748    initAdjust();
1749    themeColorMeta = document.querySelector('meta[name="theme-color"]');
1750    pageHeaderEl = document.getElementById("page-header");
1751    navMusicEl = document.getElementById("nav-music");
1752    consoleEl = document.getElementById("console");
1753
1754    addDarkModeEventListener("console", ".darkmode_switchbutton");
1755
1756    if (GLOBAL_CONFIG_SITE.isPost) {
1757      GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice();
1758      GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll("#post-meta time"));
1759    } else {
1760      if (GLOBAL_CONFIG.relativeDate.homepage) {
1761        relativeDate(document.querySelectorAll("#recent-posts time"));
1762      } else if (GLOBAL_CONFIG.relativeDate.simplehomepage) {
1763        relativeDate(document.querySelectorAll("#recent-posts time"), true);
1764      }
1765      GLOBAL_CONFIG.runtime && addRuntime();
1766      addLastPushDate();
1767      toggleCardCategory();
1768    }
1769
1770    GLOBAL_CONFIG.diytitle && changeDocumentTitle();
1771    scrollFnToDo();
1772    GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex();
1773    addHighlightTool();
1774    GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption();
1775    scrollFn();
1776
1777    // 刷新时第一次滚动百分比
1778    window.scrollCollect && window.scrollCollect();
1779
1780    const $jgEle = document.querySelectorAll("#content-inner .fj-gallery");
1781    $jgEle.length && runJustifiedGallery($jgEle);
1782
1783    runLightbox();
1784    addTableWrap();
1785    clickFnOfTagHide();
1786    tabsFn();
1787    switchComments();
1788    document.getElementById("toggle-menu").addEventListener("click", () => {
1789      sidebarFn.open();
1790    });
1791
1792    // 如果当前页有评论就执行函数
1793    if (document.getElementById("post-comment")) owoBig();
1794
1795    mouseleaveHomeCard();
1796    coverColor();
1797    listenToPageInputPress();
1798    openMobileMenu();
1799
1800    // needRefresh
1801    // nav中间的标题变化
1802    document.getElementById("page-name").innerText = document.title.split(` | ${GLOBAL_CONFIG_SITE.configTitle}`)[0];
1803    anzhiyu.initIndexEssay();
1804    anzhiyu.changeTimeInEssay();
1805    anzhiyu.removeBodyPaceClass();
1806    anzhiyu.qrcodeCreate();
1807    anzhiyu.changeTimeInAlbumDetail();
1808    anzhiyu.reflashEssayWaterFall();
1809    anzhiyu.sayhi();
1810    anzhiyu.stopImgRightDrag();
1811    anzhiyu.addNavBackgroundInit();
1812    anzhiyu.setValueToBodyType();
1813    anzhiyu.catalogActive();
1814    anzhiyu.tagsPageActive();
1815    anzhiyu.categoriesBarActive();
1816    anzhiyu.topCategoriesBarScroll();
1817    anzhiyu.switchRightClickMenuHotReview();
1818    anzhiyu.getCustomPlayList();
1819    anzhiyu.addEventListenerConsoleMusicList(false);
1820    anzhiyu.initPaginationObserver();
1821
1822    setTimeout(() => {
1823      setInputFocusListener();
1824      if (typeof addFriendLinksInFooter === "function") {
1825        addFriendLinksInFooter();
1826      }
1827    }, 200);
1828  };
1829
1830  refreshFn();
1831  unRefreshFn();
1832});

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.