Fix double double quotes when copying chat message text in Firefox

34ff8e239f580b0aa51307f091e529c13a71335d

maver <christian.pahren@googlemail.com>

2 files changed, +54 -0Ignore whitespace
public/script.js+2 -0
@@ -247,6 +247,7 @@ import { AbortReason } from './scripts/util/AbortReason.js';
247import { initSystemPrompts } from './scripts/sysprompt.js';247import { initSystemPrompts } from './scripts/sysprompt.js';
248import { registerExtensionSlashCommands as initExtensionSlashCommands } from './scripts/extensions-slashcommands.js';248import { registerExtensionSlashCommands as initExtensionSlashCommands } from './scripts/extensions-slashcommands.js';
249import { ToolManager } from './scripts/tool-calling.js';249import { ToolManager } from './scripts/tool-calling.js';
250import { applyBrowserFixes } from './scripts/browser-fixes.js';
250251
251//exporting functions and vars for mods252//exporting functions and vars for mods
252export {253export {
@@ -272,6 +273,7 @@ await new Promise((resolve) => {
272});273});
273274
274showLoader();275showLoader();
276applyBrowserFixes();
275277
276// Configure toast library:278// Configure toast library:
277toastr.options.escapeHtml = true; // Prevent raw HTML inserts279toastr.options.escapeHtml = true; // Prevent raw HTML inserts
public/scripts/browser-fixes.js+52 -0
@@ -0,0 +1,52 @@
1const isFirefox = () => /firefox/i.test(navigator.userAgent);
2
3function sanitizeInlineQuotationOnCopy() {
4 // STRG+C, STRG+V on firefox leads to duplicate double quotes when inline quotation elements are copied.
5 // To work around this, take the selection and transform <q> to <span> before calling toString().
6 document.addEventListener('copy', function (event) {
7 const selection = window.getSelection();
8 if (selection.anchorNode.nodeName !== '#text' || selection.focusNode.nodeName !== '#text' || !selection.anchorNode?.parentElement.closest('.mes_text')) {
9 // Complex selection, skip.
10 return;
11 }
12
13 const range = selection.getRangeAt(0).cloneContents();
14 const tempDOM = document.createDocumentFragment();
15
16 function processNode(node) {
17 if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'q') {
18 // Transform <q> to <span>, preserve children
19 const span = document.createElement('span');
20
21 [...node.childNodes].forEach(child => {
22 const processedChild = processNode(child);
23 span.appendChild(processedChild);
24 });
25
26 return span;
27 } else {
28 // Nested structures containing <q> elements are unlikely
29 return node.cloneNode(true);
30 }
31 }
32
33 [...range.childNodes].forEach(child => {
34 const processedChild = processNode(child);
35 tempDOM.appendChild(processedChild);
36 });
37
38 const newRange = document.createRange();
39 newRange.selectNodeContents(tempDOM);
40
41 event.preventDefault();
42 event.clipboardData.setData('text/plain', newRange.toString());
43 });
44}
45
46function applyBrowserFixes() {
47 if (isFirefox()) {
48 sanitizeInlineQuotationOnCopy();
49 }
50}
51
52export { isFirefox, applyBrowserFixes };