/** * Initialize variables */ // for tracking notebook url let notebookLocation = window.location.href; // for tracking the scrollbar position let scrollPercentage = 0; let lastWidth = window.innerWidth; /** * Helper: Standard Debounce Function */ function debounce(func, wait) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; } function windowScrolled(_event) { const maxScroll = document.documentElement.scrollHeight - window.innerHeight; if (maxScroll > 0) { scrollPercentage = window.scrollY / maxScroll; } } /** * windowResized is called when the browser window is resized. * It adjusts the scroll position to maintain approximately the same visible portion of the page. */ const windowResized = debounce(() => { // console.log('window resized...') const currentWidth = window.innerWidth; // Only adjust if the width actually changed if (currentWidth !== lastWidth) { lastWidth = currentWidth; const newMaxScroll = document.documentElement.scrollHeight - window.innerHeight; const newScrollTop = scrollPercentage * newMaxScroll; window.scrollTo({ top: newScrollTop, behavior: 'smooth' // Or 'auto' }); } }, 200); // 200ms delay after the last resize event /** * clickCallback handles clicks on links to prevent default browser navigation. * It checks if the clicked link points to the current page or a different one. * For same page links, it updates window.location.href to navigate. * For external links, it opens the URL in a new tab/window. */ function clickCallback(event) { // console.log(`Notebook location ${notebookLocation}`); if (event.target.tagName !== 'A') return; event.preventDefault(); const link = event.target.href; if (link.startsWith(notebookLocation)) { // console.log("same page"); window.location.href = link; } else { // console.log("different page"); window.open(link, '_blank'); } } /** * Adds a copy button to code cells to allow copying cell contents. * Searches for code cells with selectors and inserts a copy button. */ function addCopyThisButton() { // Add a 'copy this' button to every code cell // The bottons are added just before the code cells with the classes specified in 'selectors' let selectors = [".hl-ipython2", ".hl-ipython3"]; let html = ""; let cells; for (let selector of selectors) { cells = []; cells = document.querySelectorAll(selector); cells.forEach(cell => cell.insertAdjacentHTML("beforebegin", html)); } } /** * domLoaded is called when the DOM has loaded. * It sets up event listeners and calls addCopyThisButton to add copy buttons. */ function domLoaded() { addCopyThisButton(); notebookLocation = window.location.href; // Add event listeners window.addEventListener('scroll', windowScrolled); window.addEventListener('resize', windowResized); if (document.addEventListener) document.addEventListener('click', clickCallback, false); else document.attachEvent('onclick', clickCallback); // add the logic for copying the content of the code cells to the clipboard // courtesy of https://clipboardjs.com/ let clipboard = new ClipboardJS('.copy-code-btn', { target: function(trigger) { return trigger.nextElementSibling; } }); // what do do after the item has been copied to the clipboard clipboard.on('success', function(e) { let trigger = e.trigger; e.clearSelection(); const btnTextBackup = trigger.innerHTML; trigger.disabled = true; trigger.innerText = 'Copied!'; setTimeout(() => { trigger.innerHTML = btnTextBackup; trigger.disabled = false; }, 2000); }); } // what to do when the DOM has loaded document.addEventListener("DOMContentLoaded", domLoaded);