1// Localization support 2const messages = { 3 'en': { 4 'copy': 'Copy', 5 'copy_to_clipboard': 'Copy to clipboard', 6 'copy_success': 'Copied!', 7 'copy_failure': 'Failed to copy', 8 }, 9 'es' : { 10 'copy': 'Copiar', 11 'copy_to_clipboard': 'Copiar al portapapeles', 12 'copy_success': '¡Copiado!', 13 'copy_failure': 'Error al copiar', 14 }, 15 'de' : { 16 'copy': 'Kopieren', 17 'copy_to_clipboard': 'In die Zwischenablage kopieren', 18 'copy_success': 'Kopiert!', 19 'copy_failure': 'Fehler beim Kopieren', 20 }, 21 'fr' : { 22 'copy': 'Copier', 23 'copy_to_clipboard': 'Copié dans le presse-papier', 24 'copy_success': 'Copié !', 25 'copy_failure': 'Ãchec de la copie', 26 }, 27 'ru': { 28 'copy': 'СкопиÑоваÑÑ', 29 'copy_to_clipboard': 'СкопиÑоваÑÑ Ð² бÑÑеÑ', 30 'copy_success': 'СкопиÑовано!', 31 'copy_failure': 'Ðе ÑдалоÑÑ ÑкопиÑоваÑÑ', 32 }, 33 'zh-CN': { 34 'copy': 'å¤å¶', 35 'copy_to_clipboard': 'å¤å¶å°åªè´´æ¿', 36 'copy_success': 'å¤å¶æå!', 37 'copy_failure': 'å¤å¶å¤±è´¥', 38 }, 39 'it' : { 40 'copy': 'Copiare', 41 'copy_to_clipboard': 'Copiato negli appunti', 42 'copy_success': 'Copiato!', 43 'copy_failure': 'Errore durante la copia', 44 } 45} 46 47let locale = 'en' 48if( document.documentElement.lang !== undefined 49 && messages[document.documentElement.lang] !== undefined ) { 50 locale = document.documentElement.lang 51} 52 53let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; 54if (doc_url_root == '#') { 55 doc_url_root = ''; 56} 57 58/** 59 * SVG files for our copy buttons 60 */ 61let iconCheck = `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-check" width="44" height="44" viewBox="0 0 24 24" stroke-width="2" stroke="#22863a" fill="none" stroke-linecap="round" stroke-linejoin="round"> 62 <title>${messages[locale]['copy_success']}</title> 63 <path stroke="none" d="M0 0h24v24H0z" fill="none"/> 64 <path d="M5 12l5 5l10 -10" /> 65</svg>` 66 67// If the user specified their own SVG use that, otherwise use the default 68let iconCopy = ``; 69if (!iconCopy) { 70 iconCopy = `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copy" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#000000" fill="none" stroke-linecap="round" stroke-linejoin="round"> 71 <title>${messages[locale]['copy_to_clipboard']}</title> 72 <path stroke="none" d="M0 0h24v24H0z" fill="none"/> 73 <rect x="8" y="8" width="12" height="12" rx="2" /> 74 <path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" /> 75</svg>` 76} 77 78/** 79 * Set up copy/paste for code blocks 80 */ 81 82const runWhenDOMLoaded = cb => { 83 if (document.readyState != 'loading') { 84 cb() 85 } else if (document.addEventListener) { 86 document.addEventListener('DOMContentLoaded', cb) 87 } else { 88 document.attachEvent('onreadystatechange', function() { 89 if (document.readyState == 'complete') cb() 90 }) 91 } 92} 93 94const codeCellId = index => `codecell${index}` 95 96// Clears selected text since ClipboardJS will select the text when copying 97const clearSelection = () => { 98 if (window.getSelection) { 99 window.getSelection().removeAllRanges() 100 } else if (document.selection) { 101 document.selection.empty() 102 } 103} 104 105// Changes tooltip text for two seconds, then changes it back 106const temporarilyChangeTooltip = (el, oldText, newText) => { 107 el.setAttribute('data-tooltip', newText) 108 el.classList.add('success') 109 setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) 110 setTimeout(() => el.classList.remove('success'), 2000) 111} 112 113// Changes the copy button icon for two seconds, then changes it back 114const temporarilyChangeIcon = (el) => { 115 el.innerHTML = iconCheck; 116 setTimeout(() => {el.innerHTML = iconCopy}, 2000) 117} 118 119const addCopyButtonToCodeCells = () => { 120 // If ClipboardJS hasn't loaded, wait a bit and try again. This 121 // happens because we load ClipboardJS asynchronously. 122 if (window.ClipboardJS === undefined) { 123 setTimeout(addCopyButtonToCodeCells, 250) 124 return 125 } 126 127 // Add copybuttons to all of our code cells 128 const codeCells = document.querySelectorAll('div.highlight pre')
129 codeCells.forEach((codeCell, index) => { 130 const id = codeCellId(index) 131 codeCell.setAttribute('id', id) 132 133 const clipboardButton = id => 134 `<button class="copybtn o-tooltip--left" data-tooltip="${messages[locale]['copy']}" data-clipboard-target="#${id}"> 135 ${iconCopy} 136 </button>` 137 codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) 138 }) 139 140function escapeRegExp(string) { 141 return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string 142} 143 144// Callback when a copy button is clicked. Will be passed the node that was clicked 145// should then grab the text and replace pieces of text that shouldn't be used in output 146function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { 147 148 var regexp; 149 var match; 150 151 // Do we check for line continuation characters and "HERE-documents"? 152 var useLineCont = !!lineContinuationChar 153 var useHereDoc = !!hereDocDelim 154 155 // create regexp to capture prompt and remaining line 156 if (isRegexp) { 157 regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') 158 } else { 159 regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') 160 } 161 162 const outputLines = []; 163 var promptFound = false; 164 var gotLineCont = false; 165 var gotHereDoc = false; 166 const lineGotPrompt = []; 167 for (const line of textContent.split('\n')) { 168 match = line.match(regexp) 169 if (match || gotLineCont || gotHereDoc) { 170 promptFound = regexp.test(line) 171 lineGotPrompt.push(promptFound) 172 if (removePrompts && promptFound) { 173 outputLines.push(match[2]) 174 } else { 175 outputLines.push(line) 176 } 177 gotLineCont = line.endsWith(lineContinuationChar) & useLineCont 178 if (line.includes(hereDocDelim) & useHereDoc) 179 gotHereDoc = !gotHereDoc 180 } else if (!onlyCopyPromptLines) { 181 outputLines.push(line) 182 } else if (copyEmptyLines && line.trim() === '') { 183 outputLines.push(line) 184 } 185 } 186 187 // If no lines with the prompt were found then just use original lines 188 if (lineGotPrompt.some(v => v === true)) { 189 textContent = outputLines.join('\n'); 190 } 191 192 // Remove a trailing newline to avoid auto-running when pasting 193 if (textContent.endsWith("\n")) { 194 textContent = textContent.slice(0, -1) 195 } 196 return textContent 197} 198 199 200var copyTargetText = (trigger) => { 201 var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); 202 return formatCopyText(target.innerText, '', false, true, true, true, '', '') 203} 204 205 // Initialize with a callback so we can modify the text before copy 206 const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) 207 208 // Update UI with error/success messages 209 clipboard.on('success', event => { 210 clearSelection() 211 temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) 212 temporarilyChangeIcon(event.trigger) 213 }) 214 215 clipboard.on('error', event => { 216 temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) 217 }) 218} 219 220runWhenDOMLoaded(addCopyButtonToCodeCells)
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.