123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // Localization support
- const messages = {
- 'en': {
- 'copy': 'Copy',
- 'copy_to_clipboard': 'Copy to clipboard',
- 'copy_success': 'Copied!',
- 'copy_failure': 'Failed to copy',
- },
- 'es' : {
- 'copy': 'Copiar',
- 'copy_to_clipboard': 'Copiar al portapapeles',
- 'copy_success': '¡Copiado!',
- 'copy_failure': 'Error al copiar',
- },
- 'de' : {
- 'copy': 'Kopieren',
- 'copy_to_clipboard': 'In die Zwischenablage kopieren',
- 'copy_success': 'Kopiert!',
- 'copy_failure': 'Fehler beim Kopieren',
- },
- 'fr' : {
- 'copy': 'Copier',
- 'copy_to_clipboard': 'Copié dans le presse-papier',
- 'copy_success': 'Copié !',
- 'copy_failure': 'Échec de la copie',
- },
- 'ru': {
- 'copy': 'Скопировать',
- 'copy_to_clipboard': 'Скопировать в буфер',
- 'copy_success': 'Скопировано!',
- 'copy_failure': 'Не удалось скопировать',
- },
- 'zh-CN': {
- 'copy': '复制',
- 'copy_to_clipboard': '复制到剪贴板',
- 'copy_success': '复制成功!',
- 'copy_failure': '复制失败',
- },
- 'it' : {
- 'copy': 'Copiare',
- 'copy_to_clipboard': 'Copiato negli appunti',
- 'copy_success': 'Copiato!',
- 'copy_failure': 'Errore durante la copia',
- }
- }
- let locale = 'en'
- if( document.documentElement.lang !== undefined
- && messages[document.documentElement.lang] !== undefined ) {
- locale = document.documentElement.lang
- }
- let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT;
- if (doc_url_root == '#') {
- doc_url_root = '';
- }
- /**
- * SVG files for our copy buttons
- */
- let 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">
- <title>${messages[locale]['copy_success']}</title>
- <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
- <path d="M5 12l5 5l10 -10" />
- </svg>`
- // If the user specified their own SVG use that, otherwise use the default
- let iconCopy = ``;
- if (!iconCopy) {
- 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">
- <title>${messages[locale]['copy_to_clipboard']}</title>
- <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
- <rect x="8" y="8" width="12" height="12" rx="2" />
- <path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" />
- </svg>`
- }
- /**
- * Set up copy/paste for code blocks
- */
- const runWhenDOMLoaded = cb => {
- if (document.readyState != 'loading') {
- cb()
- } else if (document.addEventListener) {
- document.addEventListener('DOMContentLoaded', cb)
- } else {
- document.attachEvent('onreadystatechange', function() {
- if (document.readyState == 'complete') cb()
- })
- }
- }
- const codeCellId = index => `codecell${index}`
- // Clears selected text since ClipboardJS will select the text when copying
- const clearSelection = () => {
- if (window.getSelection) {
- window.getSelection().removeAllRanges()
- } else if (document.selection) {
- document.selection.empty()
- }
- }
- // Changes tooltip text for two seconds, then changes it back
- const temporarilyChangeTooltip = (el, oldText, newText) => {
- el.setAttribute('data-tooltip', newText)
- el.classList.add('success')
- setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000)
- setTimeout(() => el.classList.remove('success'), 2000)
- }
- // Changes the copy button icon for two seconds, then changes it back
- const temporarilyChangeIcon = (el) => {
- el.innerHTML = iconCheck;
- setTimeout(() => {el.innerHTML = iconCopy}, 2000)
- }
- const addCopyButtonToCodeCells = () => {
- // If ClipboardJS hasn't loaded, wait a bit and try again. This
- // happens because we load ClipboardJS asynchronously.
- if (window.ClipboardJS === undefined) {
- setTimeout(addCopyButtonToCodeCells, 250)
- return
- }
- // Add copybuttons to all of our code cells
- const codeCells = document.querySelectorAll('div.highlight pre')
- codeCells.forEach((codeCell, index) => {
- const id = codeCellId(index)
- codeCell.setAttribute('id', id)
- const clipboardButton = id =>
- `<button class="copybtn o-tooltip--left" data-tooltip="${messages[locale]['copy']}" data-clipboard-target="#${id}">
- ${iconCopy}
- </button>`
- codeCell.insertAdjacentHTML('afterend', clipboardButton(id))
- })
- function escapeRegExp(string) {
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
- }
- // Callback when a copy button is clicked. Will be passed the node that was clicked
- // should then grab the text and replace pieces of text that shouldn't be used in output
- function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") {
- var regexp;
- var match;
- // Do we check for line continuation characters and "HERE-documents"?
- var useLineCont = !!lineContinuationChar
- var useHereDoc = !!hereDocDelim
- // create regexp to capture prompt and remaining line
- if (isRegexp) {
- regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)')
- } else {
- regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)')
- }
- const outputLines = [];
- var promptFound = false;
- var gotLineCont = false;
- var gotHereDoc = false;
- const lineGotPrompt = [];
- for (const line of textContent.split('\n')) {
- match = line.match(regexp)
- if (match || gotLineCont || gotHereDoc) {
- promptFound = regexp.test(line)
- lineGotPrompt.push(promptFound)
- if (removePrompts && promptFound) {
- outputLines.push(match[2])
- } else {
- outputLines.push(line)
- }
- gotLineCont = line.endsWith(lineContinuationChar) & useLineCont
- if (line.includes(hereDocDelim) & useHereDoc)
- gotHereDoc = !gotHereDoc
- } else if (!onlyCopyPromptLines) {
- outputLines.push(line)
- } else if (copyEmptyLines && line.trim() === '') {
- outputLines.push(line)
- }
- }
- // If no lines with the prompt were found then just use original lines
- if (lineGotPrompt.some(v => v === true)) {
- textContent = outputLines.join('\n');
- }
- // Remove a trailing newline to avoid auto-running when pasting
- if (textContent.endsWith("\n")) {
- textContent = textContent.slice(0, -1)
- }
- return textContent
- }
- var copyTargetText = (trigger) => {
- var target = document.querySelector(trigger.attributes['data-clipboard-target'].value);
- return formatCopyText(target.innerText, '', false, true, true, true, '', '')
- }
- // Initialize with a callback so we can modify the text before copy
- const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText})
- // Update UI with error/success messages
- clipboard.on('success', event => {
- clearSelection()
- temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success'])
- temporarilyChangeIcon(event.trigger)
- })
- clipboard.on('error', event => {
- temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure'])
- })
- }
- runWhenDOMLoaded(addCopyButtonToCodeCells)
|