{"version":3,"sources":["jsdelivr-header.js","/npm/hexo-theme-next@8.27.0/source/js/utils.js"],"names":[],"mappings":"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","file":"/npm/hexo-theme-next@8.27.0/source/js/utils.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/hexo-theme-next@8.27.0/source/js/utils.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/* global NexT, CONFIG */\n\nHTMLElement.prototype.wrap = function(wrapper) {\n  this.parentNode.insertBefore(wrapper, this);\n  this.parentNode.removeChild(this);\n  wrapper.appendChild(this);\n};\n\n(function() {\n  const onPageLoaded = () => document.dispatchEvent(\n    new Event('page:loaded', {\n      bubbles: true\n    })\n  );\n\n  document.addEventListener('DOMContentLoaded', onPageLoaded);\n  document.addEventListener('pjax:success', onPageLoaded);\n})();\n\nNexT.utils = {\n\n  registerExtURL() {\n    document.querySelectorAll('span.exturl').forEach(element => {\n      const link = document.createElement('a');\n      // https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings\n      link.href = decodeURIComponent(atob(element.dataset.url).split('').map(c => {\n        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\n      }).join(''));\n      link.rel = 'noopener external nofollow noreferrer';\n      link.target = '_blank';\n      link.className = element.className;\n      link.title = element.title;\n      link.innerHTML = element.innerHTML;\n      element.parentNode.replaceChild(link, element);\n    });\n  },\n\n  registerCopyButton(target, element, code = '') {\n    // One-click copy code support.\n    target.insertAdjacentHTML('beforeend', '<div class=\"copy-btn\"><i class=\"fa fa-copy fa-fw\"></i></div>');\n    const button = target.querySelector('.copy-btn');\n    button.addEventListener('click', async () => {\n      if (!code) {\n        const lines = element.querySelector('.code') || element.querySelector('code');\n        code = lines.innerText;\n      }\n      if (navigator.clipboard) {\n        // https://caniuse.com/mdn-api_clipboard_writetext\n        try {\n          await navigator.clipboard.writeText(code);\n          button.querySelector('i').className = 'fa fa-check-circle fa-fw';\n        } catch {\n          button.querySelector('i').className = 'fa fa-times-circle fa-fw';\n        }\n      } else {\n        button.querySelector('i').className = 'fa fa-times-circle fa-fw';\n      }\n    });\n    // If copycode.style is not mac, element is larger than target\n    // So we need to accept both of them as parameters\n    element.addEventListener('mouseleave', () => {\n      setTimeout(() => {\n        button.querySelector('i').className = 'fa fa-copy fa-fw';\n      }, 300);\n    });\n  },\n\n  registerCodeblock(element) {\n    const inited = !!element;\n    let figure;\n    if (CONFIG.hljswrap) {\n      figure = (inited ? element : document).querySelectorAll('figure.highlight');\n    } else {\n      figure = document.querySelectorAll('pre');\n    }\n    figure.forEach(element => {\n      // Skip pre > .mermaid for folding and copy button\n      if (element.querySelector('.mermaid')) return;\n      const languageName = [...element.classList].find(cls => cls !== 'highlight');\n      if (!inited) {\n        let span = element.querySelectorAll('.code .line span');\n        if (span.length === 0) {\n          // Hljs without line_number and wrap\n          span = element.querySelectorAll('code.highlight span');\n        }\n        span.forEach(s => {\n          s.classList.forEach(name => {\n            s.classList.replace(name, `hljs-${name}`);\n          });\n        });\n      }\n      const height = parseInt(window.getComputedStyle(element).height, 10);\n      const needFold = CONFIG.codeblock.fold.enable && (height > CONFIG.codeblock.fold.height);\n      if (!needFold && !CONFIG.codeblock.copy_button.enable && !CONFIG.codeblock.language) return;\n      let target;\n      if (CONFIG.hljswrap && CONFIG.codeblock.copy_button.style === 'mac') {\n        target = element;\n      } else {\n        let box = element.querySelector('.code-container');\n        if (!box) {\n          // https://github.com/next-theme/hexo-theme-next/issues/98\n          // https://github.com/next-theme/hexo-theme-next/pull/508\n          const container = element.querySelector('.table-container') || element;\n          box = document.createElement('div');\n          box.className = 'code-container';\n          container.wrap(box);\n\n          // add \"notranslate\" to prevent Google Translate from translating it, which also completely messes up the layout\n          box.classList.add('notranslate');\n        }\n        target = box;\n      }\n      if (needFold && !target.classList.contains('unfold')) {\n        target.classList.add('highlight-fold');\n        target.insertAdjacentHTML('beforeend', '<div class=\"fold-cover\"></div><div class=\"expand-btn\"><i class=\"fa fa-angle-down fa-fw\"></i></div>');\n        target.querySelector('.expand-btn').addEventListener('click', () => {\n          target.classList.remove('highlight-fold');\n          target.classList.add('unfold');\n        });\n      }\n      if (!inited && CONFIG.codeblock.copy_button.enable) {\n        this.registerCopyButton(target, element);\n      }\n      if (!inited && CONFIG.codeblock.language && languageName) {\n        const lang = document.createElement('div');\n        lang.className = 'code-lang';\n        lang.innerText = languageName.toUpperCase();\n        target.insertAdjacentElement('afterbegin', lang);\n      }\n    });\n  },\n\n  wrapTableWithBox() {\n    document.querySelectorAll('table').forEach(element => {\n      const box = document.createElement('div');\n      box.className = 'table-container';\n      element.wrap(box);\n    });\n  },\n\n  registerVideoIframe() {\n    document.querySelectorAll('iframe').forEach(element => {\n      const supported = [\n        'www.youtube.com',\n        'player.vimeo.com',\n        'player.youku.com',\n        'player.bilibili.com',\n        'www.tudou.com'\n      ].some(host => element.src.includes(host));\n      if (supported && !element.parentNode.matches('.video-container')) {\n        const box = document.createElement('div');\n        box.className = 'video-container';\n        element.wrap(box);\n        const width = Number(element.width);\n        const height = Number(element.height);\n        if (width && height) {\n          box.style.paddingTop = (height / width * 100) + '%';\n        }\n      }\n    });\n  },\n\n  updateActiveNav() {\n    if (!Array.isArray(this.sections)) return;\n    let index = this.sections.findIndex(element => {\n      return element?.getBoundingClientRect().top > 10;\n    });\n    if (index === -1) {\n      index = this.sections.length - 1;\n    } else if (index > 0) {\n      index--;\n    }\n    this.activateNavByIndex(index);\n  },\n\n  registerScrollPercent() {\n    const backToTop = document.querySelector('.back-to-top');\n    const readingProgressBar = document.querySelector('.reading-progress-bar');\n    // For init back to top in sidebar if page was scrolled after page refresh.\n    window.addEventListener('scroll', () => {\n      if (backToTop || readingProgressBar) {\n        const contentHeight = document.body.scrollHeight - window.innerHeight;\n        const scrollPercent = contentHeight > 0 ? Math.min(100 * window.scrollY / contentHeight, 100) : 0;\n        if (backToTop) {\n          backToTop.classList.toggle('back-to-top-on', Math.round(scrollPercent) >= 5);\n          backToTop.querySelector('span').innerText = Math.round(scrollPercent) + '%';\n        }\n        if (readingProgressBar) {\n          readingProgressBar.style.setProperty('--progress', scrollPercent.toFixed(2) + '%');\n        }\n      }\n      this.updateActiveNav();\n    }, { passive: true });\n\n    backToTop?.addEventListener('click', () => {\n      window.anime({\n        targets  : document.scrollingElement,\n        duration : 500,\n        easing   : 'linear',\n        scrollTop: 0\n      });\n    });\n  },\n\n  /**\n   * Tabs tag listener (without twitter bootstrap).\n   */\n  registerTabsTag() {\n    // Binding `nav-tabs` & `tab-content` by real time permalink changing.\n    document.querySelectorAll('.tabs ul.nav-tabs .tab').forEach(element => {\n      element.addEventListener('click', event => {\n        event.preventDefault();\n        // Prevent selected tab to select again.\n        if (element.classList.contains('active')) return;\n        const nav = element.parentNode;\n        // Get the height of `tab-pane` which is activated before, and set it as the height of `tab-content` with extra margin / paddings.\n        const tabContent = nav.nextElementSibling;\n        tabContent.style.overflow = 'hidden';\n        tabContent.style.transition = 'height 1s';\n        // Comment system selection tab does not contain .active class.\n        const activeTab = tabContent.querySelector('.active') || tabContent.firstElementChild;\n        // Hight might be `auto`.\n        const prevHeight = parseInt(window.getComputedStyle(activeTab).height, 10) || 0;\n        const paddingTop = parseInt(window.getComputedStyle(activeTab).paddingTop, 10);\n        const marginBottom = parseInt(window.getComputedStyle(activeTab.firstElementChild).marginBottom, 10);\n        tabContent.style.height = prevHeight + paddingTop + marginBottom + 'px';\n        // Add & Remove active class on `nav-tabs` & `tab-content`.\n        [...nav.children].forEach(target => {\n          target.classList.toggle('active', target === element);\n        });\n        // https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers\n        const tActive = document.getElementById(element.querySelector('a').getAttribute('href').replace('#', ''));\n        [...tActive.parentNode.children].forEach(target => {\n          target.classList.toggle('active', target === tActive);\n        });\n        // Trigger event\n        tActive.dispatchEvent(new Event('tabs:click', {\n          bubbles: true\n        }));\n        // Get the height of `tab-pane` which is activated now.\n        const hasScrollBar = document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight);\n        const currHeight = parseInt(window.getComputedStyle(tabContent.querySelector('.active')).height, 10);\n        // Reset the height of `tab-content` and see the animation.\n        tabContent.style.height = currHeight + paddingTop + marginBottom + 'px';\n        // Change the height of `tab-content` may cause scrollbar show / disappear, which may result in the change of the `tab-pane`'s height\n        setTimeout(() => {\n          if ((document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight)) !== hasScrollBar) {\n            tabContent.style.transition = 'height 0.3s linear';\n            // After the animation, we need reset the height of `tab-content` again.\n            const currHeightAfterScrollBarChange = parseInt(window.getComputedStyle(tabContent.querySelector('.active')).height, 10);\n            tabContent.style.height = currHeightAfterScrollBarChange + paddingTop + marginBottom + 'px';\n          }\n          // Remove all the inline styles, and let the height be adaptive again.\n          setTimeout(() => {\n            tabContent.style.transition = '';\n            tabContent.style.height = '';\n          }, 250);\n        }, 1000);\n        if (!CONFIG.stickytabs) return;\n        const offset = nav.parentNode.getBoundingClientRect().top + window.scrollY + 10;\n        window.anime({\n          targets  : document.scrollingElement,\n          duration : 500,\n          easing   : 'linear',\n          scrollTop: offset\n        });\n      });\n    });\n\n    window.dispatchEvent(new Event('tabs:register'));\n  },\n\n  registerCanIUseTag() {\n    // Get responsive height passed from iframe.\n    window.addEventListener('message', ({ data }) => {\n      if (typeof data === 'string' && data.includes('ciu_embed')) {\n        const featureID = data.split(':')[1];\n        const height = data.split(':')[2];\n        document.querySelector(`iframe[data-feature=${featureID}]`).style.height = parseInt(height, 10) + 5 + 'px';\n      }\n    }, false);\n  },\n\n  registerActiveMenuItem() {\n    document.querySelectorAll('.menu-item a[href]').forEach(target => {\n      const isSamePath = target.pathname === location.pathname || target.pathname === location.pathname.replace('index.html', '');\n      const isSubPath = !CONFIG.root.startsWith(target.pathname) && location.pathname.startsWith(target.pathname);\n      target.classList.toggle('menu-item-active', target.hostname === location.hostname && (isSamePath || isSubPath));\n    });\n  },\n\n  registerLangSelect() {\n    const selects = document.querySelectorAll('.lang-select');\n    selects.forEach(sel => {\n      sel.value = CONFIG.page.lang;\n      sel.addEventListener('change', () => {\n        const target = sel.options[sel.selectedIndex];\n        document.querySelectorAll('.lang-select-label span').forEach(span => {\n          span.innerText = target.text;\n        });\n        // Disable Pjax to force refresh translation of menu item\n        window.location.href = target.dataset.href;\n      });\n    });\n  },\n\n  registerSidebarTOC() {\n    this.sections = [...document.querySelectorAll('.post-toc:not(.placeholder-toc) li a.nav-link')].map(element => {\n      const target = document.getElementById(decodeURI(element.getAttribute('href')).replace('#', ''));\n      // TOC item animation navigate.\n      element.addEventListener('click', event => {\n        event.preventDefault();\n        const offset = target.getBoundingClientRect().top + window.scrollY;\n        window.anime({\n          targets  : document.scrollingElement,\n          duration : 500,\n          easing   : 'linear',\n          scrollTop: offset,\n          complete : () => {\n            history.pushState(null, document.title, element.href);\n          }\n        });\n      });\n      return target;\n    });\n    this.updateActiveNav();\n  },\n\n  registerPostReward() {\n    const button = document.querySelector('.reward-container button');\n    if (!button) return;\n    button.addEventListener('click', () => {\n      document.querySelector('.post-reward').classList.toggle('active');\n    });\n  },\n\n  activateNavByIndex(index) {\n    const nav = document.querySelector('.post-toc:not(.placeholder-toc) .nav');\n    if (!nav) return;\n\n    const navItemList = nav.querySelectorAll('.nav-item');\n    const target = navItemList[index];\n    if (!target || target.classList.contains('active-current')) return;\n\n    const singleHeight = navItemList[navItemList.length - 1].offsetHeight;\n\n    nav.querySelectorAll('.active').forEach(navItem => {\n      navItem.classList.remove('active', 'active-current');\n    });\n    target.classList.add('active', 'active-current');\n\n    let activateEle = target.querySelector('.nav-child') || target.parentElement;\n    let navChildHeight = 0;\n\n    while (nav.contains(activateEle)) {\n      if (activateEle.classList.contains('nav-item')) {\n        activateEle.classList.add('active');\n      } else { // .nav-child or .nav\n        // scrollHeight isn't reliable for transitioning child items.\n        // The last nav-item in a list has a margin-bottom of 5px.\n        navChildHeight += (singleHeight * activateEle.childElementCount) + 5;\n        activateEle.style.setProperty('--height', `${navChildHeight}px`);\n      }\n      activateEle = activateEle.parentElement;\n    }\n\n    // Scrolling to center active TOC element if TOC content is taller then viewport.\n    const tocElement = document.querySelector(CONFIG.scheme === 'Pisces' || CONFIG.scheme === 'Gemini' ? '.sidebar-panel-container' : '.sidebar');\n    if (!document.querySelector('.sidebar-toc-active')) return;\n    window.anime({\n      targets  : tocElement,\n      duration : 200,\n      easing   : 'linear',\n      scrollTop: tocElement.scrollTop - (tocElement.offsetHeight / 2) + target.getBoundingClientRect().top - tocElement.getBoundingClientRect().top\n    });\n  },\n\n  updateSidebarPosition() {\n    if (window.innerWidth < 1200 || CONFIG.scheme === 'Pisces' || CONFIG.scheme === 'Gemini') return;\n    // Expand sidebar on post detail page by default, when post has a toc.\n    const hasTOC = document.querySelector('.post-toc:not(.placeholder-toc)');\n    let display = CONFIG.page.sidebar;\n    if (typeof display !== 'boolean') {\n      // There's no definition sidebar in the page front-matter.\n      display = CONFIG.sidebar.display === 'always' || (CONFIG.sidebar.display === 'post' && hasTOC);\n    }\n    if (display) {\n      window.dispatchEvent(new Event('sidebar:show'));\n    }\n  },\n\n  activateSidebarPanel(index) {\n    const sidebar = document.querySelector('.sidebar-inner');\n    const activeClassNames = ['sidebar-toc-active', 'sidebar-overview-active'];\n    if (sidebar.classList.contains(activeClassNames[index])) return;\n\n    const panelContainer = sidebar.querySelector('.sidebar-panel-container');\n    const tocPanel = panelContainer.firstElementChild;\n    const overviewPanel = panelContainer.lastElementChild;\n\n    let postTOCHeight = tocPanel.scrollHeight;\n    // For TOC activation, try to use the animated TOC height\n    if (index === 0) {\n      const nav = tocPanel.querySelector('.nav');\n      if (nav) {\n        postTOCHeight = parseInt(nav.style.getPropertyValue('--height'), 10);\n      }\n    }\n    const panelHeights = [\n      postTOCHeight,\n      overviewPanel.scrollHeight\n    ];\n    panelContainer.style.setProperty('--inactive-panel-height', `${panelHeights[1 - index]}px`);\n    panelContainer.style.setProperty('--active-panel-height', `${panelHeights[index]}px`);\n\n    sidebar.classList.replace(activeClassNames[1 - index], activeClassNames[index]);\n  },\n\n  updateFooterPosition() {\n    if (CONFIG.scheme === 'Pisces' || CONFIG.scheme === 'Gemini') return;\n    function updateFooterPosition() {\n      const footer = document.querySelector('.footer');\n      const containerHeight = document.querySelector('.main').offsetHeight + footer.offsetHeight;\n      footer.classList.toggle('footer-fixed', containerHeight <= window.innerHeight);\n    }\n\n    updateFooterPosition();\n    window.addEventListener('resize', updateFooterPosition);\n    window.addEventListener('scroll', updateFooterPosition, { passive: true });\n  },\n\n  /**\n   * Sets the CSS variable '--dialog-scrollgutter' to the specified gap value.\n   * If no gap is provided, it calculates the gap as the difference between\n   * the window's inner width and the document body's client width.\n   *\n   * @param {string} [gap] - The gap value to be set. If not provided, the\n   *                         default gap is calculated automatically.\n   */\n  setGutter(gap) {\n    document.body.style.setProperty('--dialog-scrollgutter', gap || `${window.innerWidth - document.body.clientWidth}px`);\n  },\n\n  getScript(src, options = {}, legacyCondition) {\n    if (typeof options === 'function') {\n      return this.getScript(src, {\n        condition: legacyCondition\n      }).then(options);\n    }\n    const {\n      condition = false,\n      attributes: {\n        id = '',\n        defer = false,\n        crossOrigin = '',\n        dataset = {},\n        ...otherAttributes\n      } = {},\n      parentNode = null\n    } = options;\n    const async = options.async ?? false;\n    return new Promise((resolve, reject) => {\n      if (condition) {\n        resolve();\n      } else {\n        const script = document.createElement('script');\n\n        if (id) script.id = id;\n        if (crossOrigin) script.crossOrigin = crossOrigin;\n        script.async = async;\n        script.defer = defer;\n        Object.assign(script.dataset, dataset);\n        Object.entries(otherAttributes).forEach(([name, value]) => {\n          script.setAttribute(name, String(value));\n        });\n\n        script.onload = resolve;\n        script.onerror = reject;\n\n        if (typeof src === 'object') {\n          const { url, integrity } = src;\n          script.src = url;\n          if (integrity) {\n            script.integrity = integrity;\n            script.crossOrigin = 'anonymous';\n          }\n        } else {\n          script.src = src;\n        }\n        (parentNode || document.head).appendChild(script);\n      }\n    });\n  },\n\n  loadComments(selector, legacyCallback) {\n    if (legacyCallback) {\n      return this.loadComments(selector).then(legacyCallback);\n    }\n    return new Promise(resolve => {\n      const element = document.querySelector(selector);\n      if (!CONFIG.comments.lazyload || !element) {\n        resolve();\n        return;\n      }\n      const intersectionObserver = new IntersectionObserver((entries, observer) => {\n        const entry = entries[0];\n        if (!entry.isIntersecting) return;\n\n        resolve();\n        observer.disconnect();\n      });\n      intersectionObserver.observe(element);\n    });\n  },\n\n  debounce(func, wait) {\n    let timeout;\n    return function(...args) {\n      const context = this;\n      clearTimeout(timeout);\n      timeout = setTimeout(() => func.apply(context, args), wait);\n    };\n  }\n};\n"]}