diff --git a/web-src/js/common.js b/web-src/js/common.js index 8b72ed1f..19a94b29 100644 --- a/web-src/js/common.js +++ b/web-src/js/common.js @@ -74,7 +74,7 @@ export function hasClass(element, clazz) { if (isNull(element.classList)) { return false; } - + return element.classList.contains(clazz); } @@ -541,4 +541,74 @@ export function toMap(elements, keyExtractor, valueExtractor) { export function deepCloneObject(obj) { return JSON.parse(JSON.stringify(obj)); +} + +// Reads the text, which user sees +// Default innerText doesn't work (on Chrome/Firefox), because
is treated as double new-line +// So the idea is just select text and copy it +function readUserVisibleText(elem) { + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(elem); + selection.removeAllRanges(); + selection.addRange(range); + const selectionString = selection.toString(); + selection.removeAllRanges(); + return selectionString; +} + +export function copyToClipboard(elem) { + // if new Clipboard API is available, just use it + if (navigator.clipboard) { + const selectionString = readUserVisibleText(elem); + navigator.clipboard.writeText(selectionString); + return; + } + + const targetId = '_hiddenCopyText_'; + const isInput = elem.tagName === 'INPUT' || elem.tagName === 'TEXTAREA'; + + let origSelectionStart, origSelectionEnd; + let target; + if (isInput) { + target = elem; + origSelectionStart = elem.selectionStart; + origSelectionEnd = elem.selectionEnd; + } else { + target = document.getElementById(targetId); + if (!target) { + target = document.createElement('textarea'); + target.style.position = 'absolute'; + target.style.left = '9999px'; + target.style.top = '0'; + target.id = targetId; + document.body.appendChild(target); + } + target.value = readUserVisibleText(elem); + } + + const currentFocus = document.activeElement; + target.focus(); + target.setSelectionRange(0, target.value.length); + + try { + document.execCommand('copy'); + } catch (e) { + console.error(e); + } + + if (currentFocus && typeof currentFocus.focus === 'function') { + currentFocus.focus(); + } + + if (isInput) { + elem.setSelectionRange(origSelectionStart, origSelectionEnd); + } else { + target.textContent = ''; + } + + document.body.removeChild(target); + + // for mobiles, we need to scroll down to make URL bar disappear + elem.scrollIntoView(); } \ No newline at end of file diff --git a/web-src/js/components/log_panel.vue b/web-src/js/components/log_panel.vue index fea1bc0d..963c85c0 100644 --- a/web-src/js/components/log_panel.vue +++ b/web-src/js/components/log_panel.vue @@ -6,11 +6,14 @@ 'shadow-bottom': atTop && !atBottom, 'shadow-top-bottom': !atTop && !atBottom}"> + + content_copy +