diff --git a/src/Elastic.Documentation.Site/Assets/copybutton.ts b/src/Elastic.Documentation.Site/Assets/copybutton.ts index cd2f05cb8..5613b23f7 100644 --- a/src/Elastic.Documentation.Site/Assets/copybutton.ts +++ b/src/Elastic.Documentation.Site/Assets/copybutton.ts @@ -1,5 +1,4 @@ -// Localization support -import * as ClipboardJS from 'clipboard' +import { $$ } from 'select-dom' const DOCUMENTATION_OPTIONS = { VERSION: '', @@ -97,16 +96,7 @@ if (!iconCopy) { ` } -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 ('selection' in document) { - ;(document.selection as Selection).empty() - } -} +const codeCellId = (index: number, prefix: string) => `${prefix}${index}` // Changes tooltip text for a moment, then changes it back // We want the timeout of our `success` class to be a bit shorter than the @@ -131,30 +121,45 @@ const temporarilyChangeIcon = (el) => { }, timeoutIcon) } -const addCopyButtonToCodeCells = () => { - // If ClipboardJS hasn't loaded, wait a bit and try again. This - // happens because we load ClipboardJS asynchronously. - +const addCopyButtonToCodeCells = ( + selector: string, + baseElement: ParentNode, + prefix: string +) => { // Add copybuttons to all of our code cells - const COPYBUTTON_SELECTOR = '.highlight pre' - const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + const codeCells = $$(selector, baseElement) codeCells.forEach((codeCell, index) => { if (codeCell.id) { return } - - const id = codeCellId(index) + const id = codeCellId(index, prefix) codeCell.setAttribute('id', id) + const clipboardButton = document.createElement('button') + clipboardButton.setAttribute('aria-label', 'Copy code to clipboard') + clipboardButton.className = 'copybtn o-tooltip--left' + clipboardButton.setAttribute('data-tooltip', messages[locale]['copy']) + clipboardButton.setAttribute('data-clipboard-target', `#${id}`) + clipboardButton.innerHTML = iconCopy + clipboardButton.onclick = async () => { + try { + const text = copyTargetText(clipboardButton, baseElement) + await navigator.clipboard.writeText(text) + temporarilyChangeTooltip( + clipboardButton, + messages[locale]['copy'], + messages[locale]['copy_success'] + ) + temporarilyChangeIcon(clipboardButton) + } catch (error) { + console.error(error) + } + } - const clipboardButton = (id) => - `` - codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + codeCell.insertAdjacentElement('afterend', clipboardButton) }) - function escapeRegExp(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string + function escapeRegExp(str: string) { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string } function filterText(target, excludes) { @@ -228,8 +233,8 @@ const addCopyButtonToCodeCells = () => { return textContent } - const copyTargetText = (trigger) => { - const target = document.querySelector( + const copyTargetText = (trigger, searchElement: ParentNode = document) => { + const target = searchElement.querySelector( trigger.attributes['data-clipboard-target'].value ) // get filtered text @@ -239,30 +244,12 @@ const addCopyButtonToCodeCells = () => { .join('\n') return formatCopyText(text, '', 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'] - ) - }) } -export function initCopyButton() { - addCopyButtonToCodeCells() +export function initCopyButton( + selector: string = '.highlight pre', + baseElement: ParentNode = document, + prefix: string = 'markdown-content-codecell-' +) { + addCopyButtonToCodeCells(selector, baseElement, prefix) } diff --git a/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/AskAi/AskAiSuggestions.tsx b/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/AskAi/AskAiSuggestions.tsx index 27e2ed210..98796c7cc 100644 --- a/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/AskAi/AskAiSuggestions.tsx +++ b/src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/AskAi/AskAiSuggestions.tsx @@ -4,6 +4,13 @@ import { EuiButton, useEuiTheme } from '@elastic/eui' import { css } from '@emotion/react' import * as React from 'react' +const buttonStyles = css` + border: none; + & > span { + justify-content: flex-start; + } +` + export interface AskAiSuggestion { question: string } @@ -16,15 +23,14 @@ export const AskAiSuggestions = (props: Props) => { const { submitQuestion } = useChatActions() const { setModalMode } = useModalActions() const { euiTheme } = useEuiTheme() - const buttonCss = css` - border: none; - & > span { - justify-content: flex-start; - } + + const dynamicButtonStyles = css` + ${buttonStyles} svg { color: ${euiTheme.colors.textSubdued}; } ` + return (
+ ${highlighted}
+
+