PageSourceSearch

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

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

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.