diff --git a/public/script.js b/public/script.js index dff96074c..db6b0d5bf 100644 --- a/public/script.js +++ b/public/script.js @@ -247,6 +247,7 @@ import { AbortReason } from './scripts/util/AbortReason.js'; import { initSystemPrompts } from './scripts/sysprompt.js'; import { registerExtensionSlashCommands as initExtensionSlashCommands } from './scripts/extensions-slashcommands.js'; import { ToolManager } from './scripts/tool-calling.js'; +import { applyBrowserFixes } from './scripts/browser-fixes.js'; //exporting functions and vars for mods export { @@ -272,6 +273,7 @@ await new Promise((resolve) => { }); showLoader(); +applyBrowserFixes(); // Configure toast library: toastr.options.escapeHtml = true; // Prevent raw HTML inserts diff --git a/public/scripts/browser-fixes.js b/public/scripts/browser-fixes.js new file mode 100644 index 000000000..709077831 --- /dev/null +++ b/public/scripts/browser-fixes.js @@ -0,0 +1,52 @@ +const isFirefox = () => /firefox/i.test(navigator.userAgent); + +function sanitizeInlineQuotationOnCopy() { + // STRG+C, STRG+V on firefox leads to duplicate double quotes when inline quotation elements are copied. + // To work around this, take the selection and transform to before calling toString(). + document.addEventListener('copy', function (event) { + const selection = window.getSelection(); + if (selection.anchorNode.nodeName !== '#text' || selection.focusNode.nodeName !== '#text' || !selection.anchorNode?.parentElement.closest('.mes_text')) { + // Complex selection, skip. + return; + } + + const range = selection.getRangeAt(0).cloneContents(); + const tempDOM = document.createDocumentFragment(); + + function processNode(node) { + if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'q') { + // Transform to , preserve children + const span = document.createElement('span'); + + [...node.childNodes].forEach(child => { + const processedChild = processNode(child); + span.appendChild(processedChild); + }); + + return span; + } else { + // Nested structures containing elements are unlikely + return node.cloneNode(true); + } + } + + [...range.childNodes].forEach(child => { + const processedChild = processNode(child); + tempDOM.appendChild(processedChild); + }); + + const newRange = document.createRange(); + newRange.selectNodeContents(tempDOM); + + event.preventDefault(); + event.clipboardData.setData('text/plain', newRange.toString()); + }); +} + +function applyBrowserFixes() { + if (isFirefox()) { + sanitizeInlineQuotationOnCopy(); + } +} + +export { isFirefox, applyBrowserFixes };