1// Mobile nav controls 2const navButton = document.querySelector('.nav__menu--button'); 3const closeButton = document.querySelector('.nav__menu--close'); 4const mobileNavMenu = document.querySelector('.k-nav'); 5const pageContainer = document.querySelector('.page__container'); 6 7navButton.addEventListener('click', () => { 8 mobileNavMenu.style.display = 'block'; 9 closeButton.style.display = 'block'; 10 navButton.style.display = 'none'; 11 pageContainer.style.position = 'fixed'; 12}); 13 14closeButton.addEventListener('click', () => { 15 mobileNavMenu.style.display = 'none'; 16 closeButton.style.display = 'none'; 17 navButton.style.display = 'block'; 18 pageContainer.style.position = 'static'; 19}); 20 21// Copy code 22function addCopyButtonsToCodeBlocks() { 23 // Find all code blocks with .codehilite class, excluding those inside .k-default-codeblock 24 const allCodeBlocks = document.querySelectorAll('.codehilite:not(.k-default-codeblock .codehilite)'); 25 26 allCodeBlocks.forEach((block) => { 27 // Skip if button already exists 28 if (block.querySelector('.code__copy--button')) { 29 return; 30 } 31 32 // Create copy button 33 const button = document.createElement('button'); 34 button.className = 'code__copy--button'; 35 button.setAttribute('aria-label', 'Copy code to clipboard'); 36 37 // Create icon element 38 const icon = document.createElement('i'); 39 icon.className = 'icon--copy'; 40 button.appendChild(icon); 41 42 // Create tooltip 43 const tooltip = document.createElement('div'); 44 tooltip.className = 'code__copy--tooltip'; 45 tooltip.textContent = 'Copied!'; 46 button.appendChild(tooltip); 47 48 // Add button to container 49 block.insertBefore(button, block.firstChild); 50 51 // Add click event listener 52 button.addEventListener('click', () => { 53 // Find the code element 54 const codeElement = block.querySelector('pre code') || block.querySelector('code') || block.querySelector('pre'); 55 if (!codeElement) return; 56 57 let text = codeElement.innerText || codeElement.textContent; 58 59 // Clean the text: remove Python prompts and continuation markers 60 text = cleanCodeText(text); 61 62 // Copy to clipboard using fallback method for better reliability 63 copyWithFallback(text, button); 64 }); 65 }); 66} 67 68function cleanCodeText(text) { 69 // Remove Python interactive prompt characters (>>>, ...) 70 // Split by lines, process each line, then rejoin 71 const lines = text.split('\n'); 72 const cleanedLines = lines.map(line => { 73 // Remove >>> at the start of line (with optional spaces) 74 line = line.replace(/^\s*>>>\s?/, ''); 75 // Remove ... at the start of line (with optional spaces) - continuation prompt 76 line = line.replace(/^\s*\.\.\.\s?/, ''); 77 return line; 78 }); 79 80 return cleanedLines.join('\n'); 81} 82 83function copyWithFallback(text, button) { 84 const inputElement = document.createElement('textarea'); 85 inputElement.value = text; 86 inputElement.setAttribute('readonly', ''); 87 inputElement.style.position = 'absolute'; 88 inputElement.style.left = '-9999px'; 89 document.body.appendChild(inputElement); 90 inputElement.select(); 91 92 try { 93 document.execCommand('copy'); 94 showCopyTooltip(button); 95 } catch (err) { 96 console.error('Failed to copy text:', err); 97 } 98 99 inputElement.remove(); 100} 101 102function showCopyTooltip(button) { 103 const tooltip = button.querySelector('.code__copy--tooltip'); 104 if (tooltip) { 105 tooltip.style.display = 'block'; 106 setTimeout(() => { 107 tooltip.style.display = 'none'; 108 }, 2000); 109 } 110} 111 112// Add copy buttons on page load 113document.addEventListener('DOMContentLoaded', addCopyButtonsToCodeBlocks); 114 115// Existing copy buttons (for landing page compatibility) 116const copyButtons = document.querySelectorAll('.code__copy--button'); 117copyButtons.forEach((button) => { 118 button.addEventListener('click', () => { 119 const parent = button.parentNode; 120 const text = parent.querySelector('.language-python').innerText; 121 const inputElement = document.createElement('textarea'); 122 console.log('text', text); 123 inputElement.value = text; 124 inputElement.setAttribute('class', 'visually-hidden'); 125 const body = document.body; 126 body.appendChild(inputElement); 127 inputElement.select(); 128 document.execCommand('copy'); 129 inputElement.remove(); 130 131 button.querySelector('.code__copy--tooltip').style.display = 'block'; 132 setTimeout(() => { 133 button.querySelector('.code__copy--tooltip').style.display = 'none'; 134 }, 2000); 135 }); 136}); 137 138// Search controls 139const searchForms = document.querySelectorAll('.nav__search'); 140const mobileNavSearchIcon = document.querySelector('.nav__search--mobile'); 141const mobileNavSearchForm = document.querySelector('.nav__search-form--mobile'); 142const mobileNavControls = document.querySelector('.nav__controls--mobile'); 143const desktopSearch = document.querySelector('.nav__menu .nav__search'); 144 145mobileNavSearchIcon.addEventListener('click', () => { 146 mobileNavControls.style.display = 'none'; 147 mobileNavSearchForm.style.display = 'block'; 148}); 149
150searchForms.forEach((search) => { 151 search.addEventListener('submit', (event) => { 152 event.preventDefault(); 153 const text = search.querySelector('.nav__search--input').value; 154 window.location = `/search.html?query=${text}`; 155 }); 156}); 157 158pageContainer.addEventListener('click', () => { 159 mobileNavControls.style.display = 'flex'; 160 mobileNavSearchForm.style.display = 'none'; 161}); 162 163mobileNavMenu.addEventListener('click', () => { 164 mobileNavControls.style.display = 'flex'; 165 mobileNavSearchForm.style.display = 'none'; 166}); 167 168if (window.location.pathname.indexOf('search.html') > -1) { 169 desktopSearch.style.display = 'none'; 170 mobileNavSearchIcon.style.visibility = 'hidden'; 171} 172 173// position:sticky functionality (set margin-top so that the content is correctly centered vertically) 174const exploreModule = document.querySelector('.explore'); 175const exploreContent = document.querySelector('.explore__content'); 176 177const observer = new IntersectionObserver( 178 (entries) => { 179 entries.forEach((entry) => { 180 if (entry.isIntersecting) { 181 window.addEventListener('resize', verticallyCenterExploreContent); 182 return; 183 } 184 185 window.removeEventListener('resize', verticallyCenterExploreContent); 186 }); 187 }, 188 { threshold: 0 } 189); 190 191if (exploreModule && window.innerWidth > 1199) { 192 observer.observe(exploreModule); 193 /* let's call it once initially to align it in case a screen never gets resized */ 194 verticallyCenterExploreContent(); 195} 196 197function verticallyCenterExploreContent() { 198 exploreContent.style.marginTop = `${Math.round(exploreContent.getBoundingClientRect().height / 2)}px`; 199}
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.