Merge pull request #3311 from SillyTavern/fix-http-copy Fix copy actions for non-HTTPS/localhost

df28c2c676d62d2e9791839d336a5aa823b210ec

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
2 files changed, +29 -16Showing whitespace changes
public/script.js+9 -16
@@ -168,6 +168,7 @@ import {
168168 isTrueBoolean,
169169 toggleDrawer,
170170 isElementInViewport,
171+ copyText,
171172} from './scripts/utils.js';
172173import { debounce_timeout } from './scripts/constants.js';
173174
@@ -2315,18 +2316,17 @@ export function addCopyToCodeBlocks(messageElement) {
23152316 const codeBlocks = $(messageElement).find('pre code');
23162317 for (let i = 0; i < codeBlocks.length; i++) {
23172318 hljs.highlightElement(codeBlocks.get(i));
2318- if (navigator.clipboard !== undefined) {
23192319 const copyButton = document.createElement('i');
23202320 copyButton.classList.add('fa-solid', 'fa-copy', 'code-copy', 'interactable');
23212321 copyButton.title = 'Copy code';
23222322 codeBlocks.get(i).appendChild(copyButton);
23232323 copyButton.addEventListener('pointerup', async function (event) {
23242324 navigator.clipboard.writeText( const text = codeBlocks.get(i).innerText);
2325+ await copyText(text);
23252326 toastr.info(t`Copied!`, '', { timeOut: 2000 });
23262327 });
23272328 }
23282329}
2329-}
23302330
23312331
23322332/**
@@ -5469,7 +5469,7 @@ async function promptItemize(itemizedPrompts, requestedMesId) {
54695469 } else {
54705470 diffPrevPrompt.style.display = 'none';
54715471 }
54725472 popup.dlg.querySelector('#copyPromptToClipboard').addEventListener('clickpointerup', async function () {
54735473 let rawPrompt = itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt;
54745474 let rawPromptValues = rawPrompt;
54755475
@@ -5477,7 +5477,7 @@ async function promptItemize(itemizedPrompts, requestedMesId) {
54775477 rawPromptValues = rawPrompt.map(x => x.content).join('\n');
54785478 }
54795479
54805480 navigator.clipboard.writeTextawait copyText(rawPromptValues);
54815481 toastr.info(t`Copied!`);
54825482 });
54835483
@@ -9507,7 +9507,7 @@ API Settings: ${JSON.stringify(getSettingsContents[getSettingsContents.main_api
95079507 //console.log(logMessage);
95089508
95099509 try {
95109510 await navigator.clipboard.writeTextcopyText(logMessage);
95119511 toastr.info('Your ST API setup data has been copied to the clipboard.');
95129512 } catch (error) {
95139513 toastr.error('Failed to copy ST Setup to clipboard:', error);
@@ -10572,24 +10572,18 @@ jQuery(async function () {
1057210572 setTimeout(function () { $('#shadow_select_chat_popup').css('display', 'none'); }, animation_duration);
1057310573 });
1057410574
10575- if (navigator.clipboard === undefined) {
10575+ $(document).on('pointerup', '.mes_copy', async function () {
10576- // No clipboard support
10577- $('.mes_copy').remove();
10578- }
10579- else {
10580- $(document).on('pointerup', '.mes_copy', function () {
1058110576 if (this_chid !== undefined || selected_group || name2 === neutralCharacterName) {
1058210577 try {
1058310578 const messageId = $(this).closest('.mes').attr('mesid');
1058410579 const text = chat[messageId]['mes'];
10585- navigator.clipboard.writeText(text);
10580+ await copyText(text);
1058610581 toastr.info('Copied!', '', { timeOut: 2000 });
1058710582 } catch (err) {
1058810583 console.error('Failed to copy: ', err);
1058910584 }
1059010585 }
1059110586 });
10592- }
1059310587
1059410588 $(document).on('pointerup', '.mes_prompt', async function () {
1059510589 let mesIdForItemization = $(this).closest('.mes').attr('mesId');
@@ -11483,4 +11477,3 @@ jQuery(async function () {
1148311477
1148411478 initCustomSelectedSamplers();
1148511479});
11486-
public/scripts/utils.js+20 -0
@@ -392,6 +392,26 @@ export function getStringHash(str, seed = 0) {
392392}
393393
394394/**
395+ * Copy text to clipboard. Use navigator.clipboard.writeText if available, otherwise use document.execCommand.
396+ * @param {string} text - The text to copy to the clipboard.
397+ * @returns {Promise<void>} A promise that resolves when the text has been copied to the clipboard.
398+ */
399+export function copyText(text) {
400+ if (navigator.clipboard) {
401+ return navigator.clipboard.writeText(text);
402+ }
403+
404+ const parent = document.querySelector('dialog[open]:last-of-type') ?? document.body;
405+ const textArea = document.createElement('textarea');
406+ textArea.value = text;
407+ parent.appendChild(textArea);
408+ textArea.focus();
409+ textArea.select();
410+ document.execCommand('copy');
411+ parent.removeChild(textArea);
412+}
413+
414+/**
395415 * Map of debounced functions to their timers.
396416 * Weak map is used to avoid memory leaks.
397417 * @type {WeakMap<function, any>}