{{- if (and (eq .Kind "page") (ne .Layout "archives") (ne .Layout "search") (.Param "ShowCodeCopyButtons")) }} <script> document.querySelectorAll('pre > code').forEach((codeblock) => { const container = codeblock.parentNode.parentNode; const copybutton = document.createElement('button'); copybutton.classList.add('copy-code'); copybutton.innerText = '{{- i18n "code_copy" | default "copy" }}'; function copyingDone() { copybutton.innerText = '{{- i18n "code_copied" | default "copied!" }}'; setTimeout(() => { copybutton.innerText = '{{- i18n "code_copy" | default "copy" }}'; }, 2000); } copybutton.addEventListener('click', (cb) => { if ('clipboard' in navigator) { navigator.clipboard.writeText(codeblock.textContent); copyingDone(); return; } const range = document.createRange(); range.selectNodeContents(codeblock); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); try { document.execCommand('copy'); copyingDone(); } catch (e) { }; selection.removeRange(range); }); if (container.classList.contains("highlight")) { container.appendChild(copybutton); } else if (container.parentNode.firstChild == container) { // td containing LineNos } else if (codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == "TABLE") { // table containing LineNos and code codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(copybutton); } else { // code blocks not having highlight as parent class codeblock.parentNode.appendChild(copybutton); } }); </script> {{- end }} {{/* ToC Scroll */}} <script> // NOTE use closure instead of DOMContentLoaded because of InstantClick, // every page loaded by InstantClick should run the <script> tags again. (function() { const enableTocScroll = '{{- if (and (eq .Kind "page") (.Content) (.Param "ShowToc") (.Param "TocSide")) }}1{{ end }}' == '1' // always get an array here let scrollListeners = window.scrollListeners // console.log('enable toc scroll') const headings = document.querySelectorAll('h1[id],h2[id],h3[id],h4[id],h5[id]'); const activeClass = 'active'; // Make the first header active let activeHeading = headings[0]; getLinkByHeading(activeHeading).classList.add(activeClass); const onScroll = () => { const passedHeadings = []; for (const h of headings) { // 5 px as a buffer if (getOffsetTop(h) < 5) { passedHeadings.push(h) } else { break; } } if (passedHeadings.length > 0) { newActiveHeading = passedHeadings[passedHeadings.length - 1]; } else { newActiveHeading = headings[0]; } if (activeHeading != newActiveHeading) { getLinkByHeading(activeHeading).classList.remove(activeClass); activeHeading = newActiveHeading; getLinkByHeading(activeHeading).classList.add(activeClass); } } let timer = null; const scrollListener = () => { if (timer !== null) { clearTimeout(timer) } timer = setTimeout(onScroll, 50) } window.addEventListener('scroll', scrollListener, false); scrollListeners.push(scrollListener) function getLinkByHeading(heading) { const id = encodeURI(heading.getAttribute('id')).toLowerCase(); return document.querySelector(`.toc ul li a[href="#${id}"]`); } function getOffsetTop(heading) { if (!heading.getClientRects().length) { return 0; } let rect = heading.getBoundingClientRect(); return rect.top } })(); </script> {{- if (.Param "EnableImageZoom") }} <script> mediumZoom('.entry-cover img'); mediumZoom('.post-content img'); </script> {{- end }} {{- if not (.Param "noComments") }} {{ partial "comments_js.html" . }} {{ end }}