{"version":3,"sources":["jsdelivr-header.js","/npm/hexo-theme-butterfly@5.7.0/source/js/main.js"],"names":[],"mappings":"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","file":"/npm/hexo-theme-butterfly@5.7.0/source/js/main.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.48.0.\n * Original file: /npm/hexo-theme-butterfly@5.7.0/source/js/main.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","document.addEventListener('DOMContentLoaded', () => {\r\n  let headerContentWidth, $nav\r\n  let mobileSidebarOpen = false\r\n\r\n  // rightsideScrollPercent\r\n  let goUpElement = null\r\n  let scrollPercentElement = null\r\n\r\n  const adjustMenu = init => {\r\n    let hideMenuIndex = false\r\n\r\n    if (init) {\r\n      const blogInfoWidth = Array.from(document.querySelector('#blog-info > a').children).reduce((w, i) => w + i.offsetWidth, 0)\r\n      const menusWidth = Array.from(document.getElementById('menus').children).reduce((w, i) => w + i.offsetWidth, 0)\r\n      headerContentWidth = blogInfoWidth + menusWidth\r\n      $nav = document.getElementById('nav')\r\n    }\r\n\r\n    hideMenuIndex = window.innerWidth <= 768 || headerContentWidth > $nav.offsetWidth - 120\r\n\r\n    requestAnimationFrame(() => {\r\n      $nav.classList.toggle('hide-menu', hideMenuIndex)\r\n    })\r\n  }\r\n\r\n  // 初始化header\r\n  const initAdjust = () => {\r\n    adjustMenu(true)\r\n    $nav.classList.add('show')\r\n  }\r\n\r\n  // sidebar menus\r\n  const sidebarFn = {\r\n    open: () => {\r\n      btf.overflowPaddingR.add()\r\n      btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s')\r\n      document.getElementById('sidebar-menus').classList.add('open')\r\n      mobileSidebarOpen = true\r\n    },\r\n    close: () => {\r\n      btf.overflowPaddingR.remove()\r\n      btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s')\r\n      document.getElementById('sidebar-menus').classList.remove('open')\r\n      mobileSidebarOpen = false\r\n    }\r\n  }\r\n\r\n  /**\r\n   * 首頁top_img底下的箭頭\r\n   */\r\n  const scrollDownInIndex = () => {\r\n    const handleScrollToDest = () => {\r\n      btf.scrollToDest(document.getElementById('content-inner').offsetTop, 300)\r\n    }\r\n\r\n    const $scrollDownEle = document.getElementById('scroll-down')\r\n    $scrollDownEle && btf.addEventListenerPjax($scrollDownEle, 'click', handleScrollToDest)\r\n  }\r\n\r\n  /**\r\n   * 代碼\r\n   * 只適用於Hexo默認的代碼渲染\r\n   */\r\n  const addHighlightTool = $article => {\r\n    const highLight = GLOBAL_CONFIG.highlight\r\n    if (!highLight) return\r\n\r\n    const { highlightCopy, highlightLang, highlightHeightLimit, highlightFullpage, highlightMacStyle, plugin } = highLight\r\n    const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink\r\n    const isShowTool = highlightCopy || highlightLang || isHighlightShrink !== undefined || highlightFullpage || highlightMacStyle\r\n    const isNotHighlightJs = plugin !== 'highlight.js'\r\n    const isPrismjs = plugin === 'prismjs'\r\n    const $figureHighlight = isNotHighlightJs\r\n      ? Array.from($article.querySelectorAll('code[class*=\"language-\"]')).map(code => code.parentElement)\r\n      : $article.querySelectorAll('figure.highlight')\r\n\r\n    if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return\r\n\r\n    const highlightShrinkClass = isHighlightShrink === true ? 'closed' : ''\r\n    const highlightShrinkEle = isHighlightShrink !== undefined ? '<i class=\"fas fa-angle-down expand\"></i>' : ''\r\n    const highlightCopyEle = highlightCopy ? '<i class=\"fas fa-paste copy-button\"></i>' : ''\r\n    const highlightMacStyleEle = '<div class=\"macStyle\"><div class=\"mac-close\"></div><div class=\"mac-minimize\"></div><div class=\"mac-maximize\"></div></div>'\r\n    const highlightFullpageEle = highlightFullpage ? '<i class=\"fa-solid fa-up-right-and-down-left-from-center fullpage-button\"></i>' : ''\r\n\r\n    const alertInfo = (ele, text) => {\r\n      if (GLOBAL_CONFIG.Snackbar !== undefined) {\r\n        btf.snackbarShow(text)\r\n      } else {\r\n        const newEle = document.createElement('div')\r\n        newEle.className = 'copy-notice'\r\n        newEle.textContent = text\r\n        document.body.appendChild(newEle)\r\n\r\n        const buttonRect = ele.getBoundingClientRect()\r\n        const scrollTop = window.pageYOffset || document.documentElement.scrollTop\r\n        const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft\r\n\r\n        // X-axis boundary check\r\n        const halfWidth = newEle.offsetWidth / 2\r\n        const centerLeft = buttonRect.left + scrollLeft + buttonRect.width / 2\r\n        const finalLeft = Math.max(halfWidth + 10, Math.min(window.innerWidth - halfWidth - 10, centerLeft))\r\n\r\n        // Show tooltip below button if too close to top\r\n        const normalTop = buttonRect.top + scrollTop - 40\r\n        const shouldShowBelow = buttonRect.top < 60 || normalTop < 10\r\n\r\n        const topValue = shouldShowBelow ? buttonRect.top + scrollTop + buttonRect.height + 10 : normalTop\r\n\r\n        newEle.style.cssText = `\r\n      top: ${topValue + 10}px;\r\n      left: ${finalLeft}px;\r\n      transform: translateX(-50%);\r\n      opacity: 0;\r\n      transition: opacity 0.3s ease, top 0.3s ease;\r\n    `\r\n\r\n        requestAnimationFrame(() => {\r\n          newEle.style.opacity = '1'\r\n          newEle.style.top = `${topValue}px`\r\n        })\r\n\r\n        setTimeout(() => {\r\n          newEle.style.opacity = '0'\r\n          newEle.style.top = `${topValue + 10}px`\r\n          setTimeout(() => {\r\n            newEle?.remove()\r\n          }, 300)\r\n        }, 800)\r\n      }\r\n    }\r\n\r\n    const copy = async (text, ctx) => {\r\n      try {\r\n        await navigator.clipboard.writeText(text)\r\n        alertInfo(ctx, GLOBAL_CONFIG.copy.success)\r\n      } catch (err) {\r\n        console.error('Failed to copy: ', err)\r\n        alertInfo(ctx, GLOBAL_CONFIG.copy.noSupport)\r\n      }\r\n    }\r\n\r\n    // click events\r\n    const highlightCopyFn = (ele, clickEle) => {\r\n      const $buttonParent = ele.parentNode\r\n      $buttonParent.classList.add('copy-true')\r\n      const preCodeSelector = isNotHighlightJs ? 'pre code' : 'table .code pre'\r\n      const codeElement = $buttonParent.querySelector(preCodeSelector)\r\n      if (!codeElement) return\r\n      copy(codeElement.innerText, clickEle)\r\n      $buttonParent.classList.remove('copy-true')\r\n    }\r\n\r\n    const highlightShrinkFn = ele => ele.classList.toggle('closed')\r\n\r\n    const codeFullpage = (item, clickEle) => {\r\n      const wrapEle = item.closest('figure.highlight')\r\n      const isFullpage = wrapEle.classList.toggle('code-fullpage')\r\n\r\n      document.body.style.overflow = isFullpage ? 'hidden' : ''\r\n      clickEle.classList.toggle('fa-down-left-and-up-right-to-center', isFullpage)\r\n      clickEle.classList.toggle('fa-up-right-and-down-left-from-center', !isFullpage)\r\n    }\r\n\r\n    const highlightToolsFn = e => {\r\n      const $target = e.target.classList\r\n      const currentElement = e.currentTarget\r\n      if ($target.contains('expand')) highlightShrinkFn(currentElement)\r\n      else if ($target.contains('copy-button')) highlightCopyFn(currentElement, e.target)\r\n      else if ($target.contains('fullpage-button')) codeFullpage(currentElement, e.target)\r\n    }\r\n\r\n    const expandCode = e => e.currentTarget.classList.toggle('expand-done')\r\n\r\n    // 獲取隱藏狀態下元素的真實高度\r\n    const getActualHeight = item => {\r\n      if (item.offsetHeight > 0) return item.offsetHeight\r\n\r\n      const clone = item.cloneNode(true)\r\n\r\n      clone.style.cssText = `\r\n        position: absolute !important;\r\n        visibility: hidden !important;\r\n        display: block !important;\r\n        left: 0 !important;\r\n        top: 0 !important;\r\n        pointer-events: none !important;\r\n        z-index: -1 !important;\r\n        margin: 0 !important;\r\n      `\r\n\r\n      item.parentNode.insertBefore(clone, item)\r\n      const height = clone.offsetHeight\r\n      clone.remove()\r\n      return height\r\n    }\r\n\r\n    const createEle = (lang, item) => {\r\n      const fragment = document.createDocumentFragment()\r\n\r\n      if (isShowTool) {\r\n        const hlTools = document.createElement('div')\r\n        hlTools.className = `highlight-tools ${highlightShrinkClass}`\r\n        hlTools.innerHTML = highlightMacStyleEle + highlightShrinkEle + lang + highlightCopyEle + highlightFullpageEle\r\n        btf.addEventListenerPjax(hlTools, 'click', highlightToolsFn)\r\n        fragment.appendChild(hlTools)\r\n      }\r\n\r\n      if (highlightHeightLimit && getActualHeight(item) > highlightHeightLimit + 30) {\r\n        const ele = document.createElement('div')\r\n        ele.className = 'code-expand-btn'\r\n        ele.innerHTML = '<i class=\"fas fa-angle-double-down\"></i>'\r\n        btf.addEventListenerPjax(ele, 'click', expandCode)\r\n        fragment.appendChild(ele)\r\n      }\r\n\r\n      isNotHighlightJs ? item.parentNode.insertBefore(fragment, item) : item.insertBefore(fragment, item.firstChild)\r\n    }\r\n\r\n    $figureHighlight.forEach(item => {\r\n      let langName = ''\r\n      if (isNotHighlightJs) {\r\n        const newClassName = isPrismjs ? 'prismjs' : 'default'\r\n        btf.wrap(item, 'figure', { class: `highlight ${newClassName}` })\r\n      }\r\n\r\n      if (!highlightLang) {\r\n        createEle('', item)\r\n        return\r\n      }\r\n\r\n      if (isNotHighlightJs) {\r\n        langName = isPrismjs ? item.getAttribute('data-language') || 'Code' : item.querySelector('code').getAttribute('class').replace('language-', '')\r\n      } else {\r\n        langName = item.getAttribute('class').split(' ')[1]\r\n        if (langName === 'plain' || langName === undefined) langName = 'Code'\r\n      }\r\n      createEle(`<div class=\"code-lang\">${langName}</div>`, item)\r\n    })\r\n  }\r\n\r\n  /**\r\n   * PhotoFigcaption\r\n   */\r\n  const addPhotoFigcaption = $article => {\r\n    if (!GLOBAL_CONFIG.isPhotoFigcaption) return\r\n    $article.querySelectorAll('img').forEach(item => {\r\n      const altValue = item.title || item.alt\r\n      if (!altValue) return\r\n      const ele = document.createElement('div')\r\n      ele.className = 'img-alt text-center'\r\n      ele.textContent = altValue\r\n      item.insertAdjacentElement('afterend', ele)\r\n    })\r\n  }\r\n\r\n  /**\r\n   * Lightbox\r\n   */\r\n  const runLightbox = $article => {\r\n    btf.loadLightbox($article.querySelectorAll('img:not(.no-lightbox)'))\r\n  }\r\n\r\n  /**\r\n   * justified-gallery 圖庫排版\r\n   */\r\n\r\n  const fetchUrl = async url => {\r\n    try {\r\n      const response = await fetch(url)\r\n      if (!response.ok) throw new Error(`HTTP ${response.status}`)\r\n      return await response.json()\r\n    } catch (error) {\r\n      console.error('Failed to fetch URL:', error)\r\n      throw error\r\n    }\r\n  }\r\n\r\n  const runJustifiedGallery = (container, data, config) => {\r\n    const { isButton, tabs } = config\r\n    const limit = Math.max(1, Number(config.limit) || 20)\r\n    const firstLimit = Math.max(1, Number(config.firstLimit) || limit)\r\n\r\n    const dataLength = data.length\r\n    const maxGroupKey = dataLength\r\n      ? Math.ceil(Math.max(0, dataLength - firstLimit) / limit) + 1\r\n      : 0\r\n\r\n    // Gallery configuration\r\n    const igConfig = {\r\n      gap: 5,\r\n      isConstantSize: true,\r\n      sizeRange: [150, 600],\r\n      // useResizeObserver: true,\r\n      // observeChildren: true,\r\n      useTransform: true\r\n      // useRecycle: false\r\n    }\r\n\r\n    const ig = new InfiniteGrid.JustifiedInfiniteGrid(container, igConfig)\r\n    let isLayoutHidden = false\r\n\r\n    // Utility functions\r\n    const sanitizeString = str => String(str ?? '')\r\n      .replace(/&/g, '&amp;')\r\n      .replace(/\"/g, '&quot;')\r\n      .replace(/'/g, '&#39;')\r\n      .replace(/</g, '&lt;')\r\n      .replace(/>/g, '&gt;')\r\n\r\n    const createImageItem = item => {\r\n      const alt = item.alt ? `alt=\"${sanitizeString(item.alt)}\"` : ''\r\n      const title = item.title ? `title=\"${sanitizeString(item.title)}\"` : ''\r\n      const url = item.url ? sanitizeString(item.url) : ''\r\n      return `<div class=\"item\">\r\n        <img src=\"${url}\" data-grid-maintained-target=\"true\" ${alt} ${title} />\r\n      </div>`\r\n    }\r\n\r\n    const getItems = (nextGroupKey, count, isFirst = false) => {\r\n      const startIndex = isFirst ? (nextGroupKey - 1) * count : (nextGroupKey - 2) * count + firstLimit\r\n      return data.slice(startIndex, startIndex + count).map(createImageItem)\r\n    }\r\n\r\n    // Load more button\r\n    const addLoadMoreButton = container => {\r\n      const button = document.createElement('button')\r\n      button.innerHTML = `${GLOBAL_CONFIG.infinitegrid.buttonText}<i class=\"fa-solid fa-arrow-down\"></i>`\r\n\r\n      button.addEventListener('click', () => {\r\n        button.remove()\r\n        btf.setLoading.add(container)\r\n        appendItems(ig.getGroups().length + 1, limit)\r\n      }, { once: true })\r\n\r\n      container.insertAdjacentElement('afterend', button)\r\n    }\r\n\r\n    const appendItems = (nextGroupKey, count, isFirst) => {\r\n      ig.append(getItems(nextGroupKey, count, isFirst), nextGroupKey)\r\n    }\r\n\r\n    // Event handlers\r\n    const handleRenderComplete = e => {\r\n      if (tabs) {\r\n        const parentNode = container.parentNode\r\n        if (isLayoutHidden) {\r\n          parentNode.style.visibility = 'visible'\r\n        }\r\n        if (container.offsetHeight === 0) {\r\n          parentNode.style.visibility = 'hidden'\r\n          isLayoutHidden = true\r\n        }\r\n      }\r\n\r\n      const { updated, isResize, mounted } = e\r\n      if (!updated.length || !mounted.length || isResize) return\r\n\r\n      btf.loadLightbox(container.querySelectorAll('img:not(.medium-zoom-image)'))\r\n\r\n      if (ig.getGroups().length === maxGroupKey) {\r\n        btf.setLoading.remove(container)\r\n        !tabs && ig.off('renderComplete', handleRenderComplete)\r\n        return\r\n      }\r\n\r\n      if (isButton) {\r\n        btf.setLoading.remove(container)\r\n        addLoadMoreButton(container)\r\n      }\r\n    }\r\n\r\n    const handleRequestAppend = btf.debounce(e => {\r\n      const nextGroupKey = (+e.groupKey || 0) + 1\r\n\r\n      if (nextGroupKey === 1) appendItems(nextGroupKey, firstLimit, true)\r\n      else appendItems(nextGroupKey, limit)\r\n\r\n      if (nextGroupKey === maxGroupKey) ig.off('requestAppend', handleRequestAppend)\r\n    }, 300)\r\n\r\n    btf.setLoading.add(container)\r\n    ig.on('renderComplete', handleRenderComplete)\r\n\r\n    if (isButton && dataLength) {\r\n      appendItems(1, firstLimit, true)\r\n    } else if (dataLength) {\r\n      ig.on('requestAppend', handleRequestAppend)\r\n      ig.renderItems()\r\n    } else {\r\n      btf.setLoading.remove(container)\r\n    }\r\n\r\n    btf.addGlobalFn('pjaxSendOnce', () => ig.destroy())\r\n  }\r\n\r\n  const addJustifiedGallery = async (elements, tabs = false) => {\r\n    if (!elements.length) return\r\n\r\n    const initGallery = async () => {\r\n      for (const element of elements) {\r\n        if (btf.isHidden(element) || element.classList.contains('loaded')) continue\r\n\r\n        const config = {\r\n          isButton: element.getAttribute('data-button') === 'true',\r\n          limit: parseInt(element.getAttribute('data-limit'), 10),\r\n          firstLimit: parseInt(element.getAttribute('data-first'), 10),\r\n          tabs\r\n        }\r\n\r\n        const container = element.firstElementChild\r\n        const content = container.textContent\r\n        container.textContent = ''\r\n        try {\r\n          const data = element.getAttribute('data-type') === 'url' ? await fetchUrl(content) : JSON.parse(content)\r\n          if (!Array.isArray(data)) throw new TypeError('Gallery data must be an array')\r\n          runJustifiedGallery(container, data, config)\r\n          element.classList.add('loaded')\r\n        } catch (error) {\r\n          console.error('Gallery data parsing failed:', error)\r\n        }\r\n      }\r\n    }\r\n\r\n    if (typeof InfiniteGrid === 'function') {\r\n      await initGallery()\r\n    } else {\r\n      await btf.getScript(GLOBAL_CONFIG.infinitegrid.js)\r\n      await initGallery()\r\n    }\r\n  }\r\n\r\n  /**\r\n   * rightside scroll percent\r\n   */\r\n  const rightsideScrollPercent = currentTop => {\r\n    const scrollPercent = btf.getScrollPercent(currentTop, document.body)\r\n\r\n    if (!goUpElement || !scrollPercentElement) return\r\n    if (scrollPercent < 95) {\r\n      goUpElement.classList.add('show-percent')\r\n      scrollPercentElement.textContent = scrollPercent\r\n    } else {\r\n      goUpElement.classList.remove('show-percent')\r\n    }\r\n  }\r\n\r\n  /**\r\n   * 滾動處理\r\n   */\r\n  const scrollFn = () => {\r\n    const $rightside = document.getElementById('rightside')\r\n    let initTop = 0\r\n    const $header = document.getElementById('page-header')\r\n    const isChatBtn = typeof window.chatBtn !== 'undefined'\r\n    const isShowPercent = GLOBAL_CONFIG.percent.rightside\r\n\r\n    // 檢查文檔高度是否小於視窗高度\r\n    const checkDocumentHeight = () => {\r\n      if (document.body.scrollHeight <= window.innerHeight + 56) {\r\n        $rightside.classList.add('rightside-show')\r\n        return true\r\n      }\r\n      return false\r\n    }\r\n\r\n    // find the scroll direction\r\n    const scrollDirection = currentTop => {\r\n      const result = currentTop > initTop // true is down & false is up\r\n      initTop = currentTop\r\n      return result\r\n    }\r\n\r\n    let flag = ''\r\n    const scrollTask = btf.rafThrottle(() => {\r\n      if (checkDocumentHeight()) return\r\n\r\n      const currentTop = window.scrollY || document.documentElement.scrollTop\r\n      const isDown = scrollDirection(currentTop)\r\n      if (currentTop > 56) {\r\n        if (flag === '') {\r\n          $header.classList.add('nav-fixed')\r\n          $rightside.classList.add('rightside-show')\r\n        }\r\n\r\n        if (isDown) {\r\n          if (flag !== 'down') {\r\n            $header.classList.remove('nav-visible')\r\n            isChatBtn && window.chatBtn.hide()\r\n            flag = 'down'\r\n          }\r\n        } else {\r\n          if (flag !== 'up') {\r\n            $header.classList.add('nav-visible')\r\n            isChatBtn && window.chatBtn.show()\r\n            flag = 'up'\r\n          }\r\n        }\r\n      } else {\r\n        flag = ''\r\n        if (currentTop === 0) {\r\n          $header.classList.remove('nav-fixed', 'nav-visible')\r\n        }\r\n        $rightside.classList.remove('rightside-show')\r\n      }\r\n\r\n      isShowPercent && rightsideScrollPercent(currentTop)\r\n    })\r\n\r\n    checkDocumentHeight()\r\n    btf.addEventListenerPjax(window, 'scroll', scrollTask, { passive: true })\r\n  }\r\n\r\n  /**\r\n  * toc, anchor\r\n  */\r\n  const scrollFnToDo = $article => {\r\n    const isToc = GLOBAL_CONFIG_SITE.isToc\r\n    const isAnchor = GLOBAL_CONFIG.isAnchor\r\n\r\n    if (!($article && (isToc || isAnchor))) return\r\n\r\n    let $tocLink, $cardToc, autoScrollToc, $tocPercentage, isExpand\r\n\r\n    if (isToc) {\r\n      const $cardTocLayout = document.getElementById('card-toc')\r\n      $cardToc = $cardTocLayout.querySelector('.toc-content')\r\n      $tocLink = $cardToc.querySelectorAll('.toc-link')\r\n      $tocPercentage = $cardTocLayout.querySelector('.toc-percentage')\r\n      isExpand = $cardToc.classList.contains('is-expand')\r\n\r\n      const tocItemClickFn = e => {\r\n        const target = e.target.closest('.toc-link')\r\n        if (!target) return\r\n\r\n        e.preventDefault()\r\n        btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI(target.getAttribute('href')).replace('#', ''))), 300)\r\n        if (window.innerWidth < 900) {\r\n          $cardTocLayout.classList.remove('open')\r\n        }\r\n      }\r\n\r\n      btf.addEventListenerPjax($cardToc, 'click', tocItemClickFn)\r\n\r\n      autoScrollToc = item => {\r\n        const sidebarHeight = $cardToc.clientHeight\r\n        const itemOffsetTop = item.offsetTop\r\n        const itemHeight = item.clientHeight\r\n        const scrollTop = $cardToc.scrollTop\r\n        const offset = itemOffsetTop - scrollTop\r\n        const middlePosition = (sidebarHeight - itemHeight) / 2\r\n\r\n        if (offset !== middlePosition) {\r\n          $cardToc.scrollTop = scrollTop + (offset - middlePosition)\r\n        }\r\n      }\r\n\r\n      $cardToc.style.display = 'block'\r\n    }\r\n\r\n    const $articleList = $article.querySelectorAll('h1,h2,h3,h4,h5,h6')\r\n    if (!$articleList.length) return\r\n\r\n    let activeTocItem = null\r\n    let activeParentItems = []\r\n\r\n    const updateTocUI = currentId => {\r\n      const encodedAnchor = currentId ? '#' + encodeURI(decodeURI(currentId)) : ''\r\n      if (isAnchor) btf.updateAnchor(encodedAnchor)\r\n\r\n      if (!isToc) return\r\n\r\n      if (activeTocItem) activeTocItem.classList.remove('active')\r\n      activeParentItems.forEach(i => i.classList.remove('active'))\r\n      activeParentItems = []\r\n\r\n      if (!currentId) {\r\n        activeTocItem = null\r\n        return\r\n      }\r\n\r\n      const targetLink = Array.from($tocLink).find(link => {\r\n        const href = link.getAttribute('href')\r\n        if (!href) return false\r\n        return decodeURI(href).replace('#', '') === decodeURI(currentId)\r\n      })\r\n\r\n      if (!targetLink) return\r\n\r\n      targetLink.classList.add('active')\r\n      activeTocItem = targetLink\r\n      setTimeout(() => autoScrollToc(targetLink), 0)\r\n\r\n      if (!isExpand) {\r\n        let parent = targetLink.parentNode\r\n        while (!parent.matches('.toc')) {\r\n          if (parent.matches('li')) {\r\n            parent.classList.add('active')\r\n            activeParentItems.push(parent)\r\n          }\r\n          parent = parent.parentNode\r\n        }\r\n      }\r\n    }\r\n\r\n    const observerOptions = {\r\n      root: null,\r\n      rootMargin: '-60px 0px -80% 0px',\r\n      threshold: 0\r\n    }\r\n\r\n    const observer = new IntersectionObserver(entries => {\r\n      entries.forEach(entry => {\r\n        if (entry.isIntersecting) {\r\n          updateTocUI(entry.target.id)\r\n        }\r\n      })\r\n    }, observerOptions)\r\n\r\n    $articleList.forEach(ele => observer.observe(ele))\r\n\r\n    const scrollHandler = btf.rafThrottle(() => {\r\n      const currentTop = window.scrollY || document.documentElement.scrollTop\r\n\r\n      if (isToc && GLOBAL_CONFIG.percent.toc) {\r\n        $tocPercentage.textContent = btf.getScrollPercent(currentTop, $article)\r\n      }\r\n\r\n      if (currentTop === 0) {\r\n        updateTocUI('')\r\n      } else if (currentTop + window.innerHeight >= document.documentElement.scrollHeight - 10) {\r\n        const lastHeader = $articleList[$articleList.length - 1]\r\n        updateTocUI(lastHeader.id)\r\n      }\r\n    })\r\n\r\n    btf.addEventListenerPjax(window, 'scroll', scrollHandler, { passive: true })\r\n\r\n    btf.addGlobalFn('pjaxSendOnce', () => {\r\n      observer.disconnect()\r\n    })\r\n  }\r\n\r\n  const handleThemeChange = mode => {\r\n    const globalFn = window.globalFn || {}\r\n    const themeChange = globalFn.themeChange\r\n    if (!themeChange) return\r\n\r\n    Object.keys(themeChange).forEach(key => {\r\n      const fn = themeChange[key]\r\n      if (typeof fn !== 'function') return\r\n\r\n      if (['disqus', 'disqusjs'].includes(key)) {\r\n        setTimeout(() => fn(mode), 300)\r\n      } else {\r\n        fn(mode)\r\n      }\r\n    })\r\n  }\r\n\r\n  /**\r\n   * Rightside\r\n   */\r\n  const rightSideFn = {\r\n    readmode: () => { // read mode\r\n      const $body = document.body\r\n      const newEle = document.createElement('button')\r\n\r\n      const exitReadMode = () => {\r\n        $body.classList.remove('read-mode')\r\n        newEle.remove()\r\n        newEle.removeEventListener('click', exitReadMode)\r\n      }\r\n\r\n      $body.classList.add('read-mode')\r\n      newEle.type = 'button'\r\n      newEle.className = 'exit-readmode'\r\n      newEle.innerHTML = '<i class=\"fas fa-sign-out-alt\"></i>'\r\n      newEle.addEventListener('click', exitReadMode)\r\n      $body.appendChild(newEle)\r\n    },\r\n    darkmode: () => { // switch between light and dark mode\r\n      const willChangeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'\r\n      if (willChangeMode === 'dark') {\r\n        btf.activateDarkMode()\r\n        GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)\r\n      } else {\r\n        btf.activateLightMode()\r\n        GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)\r\n      }\r\n      btf.saveToLocal.set('theme', willChangeMode, 2)\r\n      handleThemeChange(willChangeMode)\r\n    },\r\n    'rightside-config': item => { // Show or hide rightside-hide-btn\r\n      const hideLayout = item.firstElementChild\r\n      if (hideLayout.classList.contains('show')) {\r\n        hideLayout.classList.add('status')\r\n        setTimeout(() => {\r\n          hideLayout.classList.remove('status')\r\n        }, 300)\r\n      }\r\n\r\n      hideLayout.classList.toggle('show')\r\n    },\r\n    'go-up': () => { // Back to top\r\n      btf.scrollToDest(0, 500)\r\n    },\r\n    'hide-aside-btn': () => { // Hide aside\r\n      const $htmlDom = document.documentElement.classList\r\n      const saveStatus = $htmlDom.contains('hide-aside') ? 'show' : 'hide'\r\n      btf.saveToLocal.set('aside-status', saveStatus, 2)\r\n      $htmlDom.toggle('hide-aside')\r\n    },\r\n    'mobile-toc-button': (p, item) => { // Show mobile toc\r\n      const tocEle = document.getElementById('card-toc')\r\n      tocEle.style.transition = 'transform 0.3s ease-in-out'\r\n\r\n      const tocEleHeight = tocEle.clientHeight\r\n      const btData = item.getBoundingClientRect()\r\n\r\n      const tocEleBottom = window.innerHeight - btData.bottom - 30\r\n      if (tocEleHeight > tocEleBottom) {\r\n        tocEle.style.transformOrigin = `right ${tocEleHeight - tocEleBottom - btData.height / 2}px`\r\n      }\r\n\r\n      tocEle.classList.toggle('open')\r\n      tocEle.addEventListener('transitionend', () => {\r\n        tocEle.style.cssText = ''\r\n      }, { once: true })\r\n    },\r\n    'chat-btn': () => { // Show chat\r\n      window.chatBtnFn()\r\n    },\r\n    translateLink: () => { // switch between traditional and simplified chinese\r\n      window.translateFn.translatePage()\r\n    }\r\n  }\r\n\r\n  document.getElementById('rightside').addEventListener('click', e => {\r\n    const $target = e.target.closest('[id]')\r\n    if ($target && rightSideFn[$target.id]) {\r\n      rightSideFn[$target.id](e.currentTarget, $target)\r\n    }\r\n  })\r\n\r\n  /**\r\n   * menu\r\n   * 側邊欄sub-menu 展開/收縮\r\n   */\r\n  const clickFnOfSubMenu = () => {\r\n    const handleClickOfSubMenu = e => {\r\n      const target = e.target.closest('.site-page.group')\r\n      if (!target) return\r\n      target.classList.toggle('hide')\r\n    }\r\n\r\n    const menusItems = document.querySelector('#sidebar-menus .menus_items')\r\n    menusItems && menusItems.addEventListener('click', handleClickOfSubMenu)\r\n  }\r\n\r\n  /**\r\n   * 手机端目录点击\r\n   */\r\n  const openMobileMenu = () => {\r\n    const toggleMenu = document.getElementById('toggle-menu')\r\n    if (!toggleMenu) return\r\n    btf.addEventListenerPjax(toggleMenu, 'click', () => { sidebarFn.open() })\r\n  }\r\n\r\n  /**\r\n * 複製時加上版權信息\r\n */\r\n  const addCopyright = () => {\r\n    const { limitCount, languages } = GLOBAL_CONFIG.copyright\r\n\r\n    const handleCopy = e => {\r\n      e.preventDefault()\r\n      const copyFont = window.getSelection(0).toString()\r\n      let textFont = copyFont\r\n      if (copyFont.length > limitCount) {\r\n        textFont = `${copyFont}\\n\\n\\n${languages.author}\\n${languages.link}${window.location.href}\\n${languages.source}\\n${languages.info}`\r\n      }\r\n      if (e.clipboardData) {\r\n        return e.clipboardData.setData('text', textFont)\r\n      } else {\r\n        return window.clipboardData.setData('text', textFont)\r\n      }\r\n    }\r\n\r\n    document.body.addEventListener('copy', handleCopy)\r\n  }\r\n\r\n  /**\r\n   * 網頁運行時間\r\n   */\r\n  const addRuntime = () => {\r\n    const $runtimeCount = document.getElementById('runtimeshow')\r\n    if ($runtimeCount) {\r\n      const publishDate = $runtimeCount.getAttribute('data-publishDate')\r\n      $runtimeCount.textContent = `${btf.diffDate(publishDate)} ${GLOBAL_CONFIG.runtime}`\r\n    }\r\n  }\r\n\r\n  /**\r\n   * 最後一次更新時間\r\n   */\r\n  const addLastPushDate = () => {\r\n    const $lastPushDateItem = document.getElementById('last-push-date')\r\n    if ($lastPushDateItem) {\r\n      const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate')\r\n      $lastPushDateItem.textContent = btf.diffDate(lastPushDate, true)\r\n    }\r\n  }\r\n\r\n  /**\r\n   * table overflow\r\n   */\r\n  const addTableWrap = $article => {\r\n    const $table = $article.querySelectorAll('table')\r\n    if (!$table.length) return\r\n\r\n    $table.forEach(item => {\r\n      if (!item.closest('.highlight')) {\r\n        btf.wrap(item, 'div', { class: 'table-wrap' })\r\n      }\r\n    })\r\n  }\r\n\r\n  const clickFnOfTagHide = $article => {\r\n    const hideButtons = $article.querySelectorAll('.hide-button')\r\n    if (!hideButtons.length) return\r\n\r\n    const handleClickOfTagHide = e => {\r\n      const button = e.target.closest('.hide-button')\r\n      if (!button) return\r\n      button.classList.add('open')\r\n      addJustifiedGallery(button.nextElementSibling.querySelectorAll('.gallery-container'))\r\n    }\r\n\r\n    btf.addEventListenerPjax($article, 'click', handleClickOfTagHide)\r\n  }\r\n\r\n  const tabsFn = $article => {\r\n    if (!$article.querySelector('.tabs')) return\r\n\r\n    const setActiveClass = (elements, activeIndex) => {\r\n      elements.forEach((el, index) => el.classList.toggle('active', index === activeIndex))\r\n    }\r\n\r\n    const handleClick = e => {\r\n      const tabsRoot = e.target.closest('.tabs')\r\n      if (!tabsRoot) return\r\n\r\n      const navContainer = tabsRoot.firstElementChild\r\n      const toTopContainer = tabsRoot.lastElementChild\r\n\r\n      if (navContainer.contains(e.target)) {\r\n        const target = e.target.closest('button')\r\n        if (!target || target.classList.contains('active')) return\r\n\r\n        const navItems = [...navContainer.children]\r\n        const tabContents = [...navContainer.nextElementSibling.children]\r\n        const indexOfButton = navItems.indexOf(target)\r\n        setActiveClass(navItems, indexOfButton)\r\n        navContainer.classList.remove('no-default')\r\n        setActiveClass(tabContents, indexOfButton)\r\n        addJustifiedGallery(tabContents[indexOfButton].querySelectorAll('.gallery-container'), true)\r\n        return\r\n      }\r\n\r\n      if (toTopContainer.contains(e.target) && e.target.closest('button')) {\r\n        btf.scrollToDest(btf.getEleTop(tabsRoot), 300)\r\n      }\r\n    }\r\n\r\n    btf.addEventListenerPjax($article, 'click', handleClick)\r\n  }\r\n\r\n  const toggleCardCategory = () => {\r\n    const cardCategory = document.querySelector('#aside-cat-list.expandBtn')\r\n    if (!cardCategory) return\r\n\r\n    const handleToggleBtn = e => {\r\n      const target = e.target\r\n      if (target.nodeName === 'I') {\r\n        e.preventDefault()\r\n        target.parentNode.classList.toggle('expand')\r\n      }\r\n    }\r\n    btf.addEventListenerPjax(cardCategory, 'click', handleToggleBtn, true)\r\n  }\r\n\r\n  const addPostOutdateNotice = () => {\r\n    const ele = document.getElementById('post-outdate-notice')\r\n    if (!ele) return\r\n\r\n    const { limitDay, messagePrev, messageNext, postUpdate } = JSON.parse(ele.getAttribute('data'))\r\n    const diffDay = btf.diffDate(postUpdate)\r\n    if (diffDay >= limitDay) {\r\n      ele.textContent = `${messagePrev} ${diffDay} ${messageNext}`\r\n      ele.hidden = false\r\n    }\r\n  }\r\n\r\n  const lazyloadImg = () => {\r\n    window.lazyLoadInstance = new LazyLoad({\r\n      elements_selector: 'img',\r\n      threshold: 0,\r\n      data_src: 'lazy-src'\r\n    })\r\n\r\n    btf.addGlobalFn('pjaxComplete', () => {\r\n      window.lazyLoadInstance.update()\r\n    }, 'lazyload')\r\n  }\r\n\r\n  const relativeDate = selector => {\r\n    selector.forEach(item => {\r\n      item.textContent = btf.diffDate(item.getAttribute('datetime'), true)\r\n      item.style.display = 'inline'\r\n    })\r\n  }\r\n\r\n  const justifiedIndexPostUI = () => {\r\n    const recentPostsElement = document.getElementById('recent-posts')\r\n    if (!(recentPostsElement && recentPostsElement.classList.contains('masonry'))) return\r\n\r\n    const init = () => {\r\n      const masonryItem = new InfiniteGrid.MasonryInfiniteGrid('.recent-post-items', {\r\n        gap: { horizontal: 10, vertical: 20 },\r\n        useTransform: true,\r\n        useResizeObserver: true\r\n      })\r\n      masonryItem.renderItems()\r\n      btf.addGlobalFn('pjaxCompleteOnce', () => { masonryItem.destroy() }, 'removeJustifiedIndexPostUI')\r\n    }\r\n\r\n    typeof InfiniteGrid === 'function' ? init() : btf.getScript(`${GLOBAL_CONFIG.infinitegrid.js}`).then(init)\r\n  }\r\n\r\n  const unRefreshFn = () => {\r\n    const resizeHandler = btf.rafThrottle(() => {\r\n      adjustMenu(false)\r\n      if (mobileSidebarOpen && btf.isHidden(document.getElementById('toggle-menu'))) {\r\n        sidebarFn.close()\r\n      }\r\n    })\r\n    window.addEventListener('resize', resizeHandler, { passive: true })\r\n\r\n    const menuMask = document.getElementById('menu-mask')\r\n    menuMask && menuMask.addEventListener('click', () => { sidebarFn.close() })\r\n\r\n    clickFnOfSubMenu()\r\n    GLOBAL_CONFIG.islazyloadPlugin && lazyloadImg()\r\n    GLOBAL_CONFIG.copyright !== undefined && addCopyright()\r\n\r\n    if (GLOBAL_CONFIG.autoDarkmode) {\r\n      window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {\r\n        if (btf.saveToLocal.get('theme') !== undefined) return\r\n        e.matches ? handleThemeChange('dark') : handleThemeChange('light')\r\n      })\r\n    }\r\n  }\r\n\r\n  const forPostFn = () => {\r\n    const $article = document.getElementById('article-container')\r\n    if (!$article || $article.querySelector('.hbe-container')) return\r\n\r\n    addHighlightTool($article)\r\n    addPhotoFigcaption($article)\r\n    addJustifiedGallery($article.querySelectorAll('.gallery-container'))\r\n    runLightbox($article)\r\n    scrollFnToDo($article)\r\n    addTableWrap($article)\r\n    clickFnOfTagHide($article)\r\n    tabsFn($article)\r\n  }\r\n\r\n  const refreshFn = () => {\r\n    initAdjust()\r\n    goUpElement = document.getElementById('go-up')\r\n    scrollPercentElement = goUpElement?.querySelector('.scroll-percent')\r\n\r\n    justifiedIndexPostUI()\r\n\r\n    if (GLOBAL_CONFIG_SITE.pageType === 'post') {\r\n      addPostOutdateNotice()\r\n      GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time'))\r\n    } else {\r\n      GLOBAL_CONFIG.relativeDate.homepage && relativeDate(document.querySelectorAll('#recent-posts time'))\r\n      GLOBAL_CONFIG.runtime && addRuntime()\r\n      addLastPushDate()\r\n      toggleCardCategory()\r\n    }\r\n\r\n    GLOBAL_CONFIG_SITE.pageType === 'home' && scrollDownInIndex()\r\n    scrollFn()\r\n\r\n    if (GLOBAL_CONFIG_SITE.pageType !== 'shuoshuo') {\r\n      forPostFn()\r\n      btf.switchComments(document)\r\n    }\r\n\r\n    openMobileMenu()\r\n  }\r\n\r\n  btf.addGlobalFn('pjaxComplete', refreshFn, 'refreshFn')\r\n  refreshFn()\r\n  unRefreshFn()\r\n\r\n  // 處理 hexo-blog-encrypt 事件\r\n  window.addEventListener('hexo-blog-decrypt', e => {\r\n    forPostFn()\r\n    window.translateFn.translateInitialization()\r\n    Object.values(window.globalFn.encrypt).forEach(fn => {\r\n      fn()\r\n    })\r\n  })\r\n\r\n  document.addEventListener('shuoshuo:rendered', forPostFn)\r\n})\r\n"]}