Merge pull request #2994 from artisticMink/fix-double-quotes Fix double double quotes when copying chat message text in Firefox

ada44497dea61f47c29c5236879e42ce5127028a

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

Signed
3 files changed, +81 -25Showing whitespace changes
public/script.js+3 -2
@@ -1,4 +1,4 @@
1import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, initRossMods, shouldSendOnEnter, addSafariPatch } from './scripts/RossAscends-mods.js';1import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, initRossMods, shouldSendOnEnter } from './scripts/RossAscends-mods.js';
2import { userStatsHandler, statMesProcess, initStats } from './scripts/stats.js';2import { userStatsHandler, statMesProcess, initStats } from './scripts/stats.js';
3import {3import {
4 generateKoboldWithStreaming,4 generateKoboldWithStreaming,
@@ -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 {
@@ -938,7 +939,7 @@ async function firstLoadInit() {
938 throw new Error('Initialization failed');939 throw new Error('Initialization failed');
939 }940 }
940941
941 addSafariPatch();942 applyBrowserFixes();
942 await getClientVersion();943 await getClientVersion();
943 await readSecretState();944 await readSecretState();
944 await initLocales();945 await initLocales();
public/scripts/RossAscends-mods.js+1 -23
@@ -121,7 +121,7 @@ export function humanizeGenTime(total_gen_time) {
121 */121 */
122var parsedUA = null;122var parsedUA = null;
123123
124function getParsedUA() {124export function getParsedUA() {
125 if (!parsedUA) {125 if (!parsedUA) {
126 try {126 try {
127 parsedUA = Bowser.parse(navigator.userAgent);127 parsedUA = Bowser.parse(navigator.userAgent);
@@ -717,18 +717,6 @@ export const autoFitSendTextAreaDebounced = debounce(autoFitSendTextArea, deboun
717717
718// ---------------------------------------------------718// ---------------------------------------------------
719719
720export function addSafariPatch() {
721 const userAgent = getParsedUA();
722 console.debug('User Agent', userAgent);
723 const isMobileSafari = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
724 const isDesktopSafari = userAgent?.browser?.name === 'Safari' && userAgent?.platform?.type === 'desktop';
725 const isIOS = userAgent?.os?.name === 'iOS';
726
727 if (isIOS || isMobileSafari || isDesktopSafari) {
728 document.body.classList.add('safari');
729 }
730}
731
732export function initRossMods() {720export function initRossMods() {
733 // initial status check721 // initial status check
734 checkStatusDebounced();722 checkStatusDebounced();
@@ -741,16 +729,6 @@ export function initRossMods() {
741 RA_autoconnect();729 RA_autoconnect();
742 }730 }
743731
744 if (isMobile()) {
745 const fixFunkyPositioning = () => {
746 console.debug('[Mobile] Device viewport change detected.');
747 document.documentElement.style.position = 'fixed';
748 requestAnimationFrame(() => document.documentElement.style.position = '');
749 };
750 window.addEventListener('resize', fixFunkyPositioning);
751 window.addEventListener('orientationchange', fixFunkyPositioning);
752 }
753
754 $('#main_api').change(function () {732 $('#main_api').change(function () {
755 var PrevAPI = main_api;733 var PrevAPI = main_api;
756 setTimeout(() => RA_autoconnect(PrevAPI), 100);734 setTimeout(() => RA_autoconnect(PrevAPI), 100);
public/scripts/browser-fixes.js+77 -0
@@ -0,0 +1,77 @@
1import { getParsedUA, isMobile } from './RossAscends-mods.js';
2
3const isFirefox = () => /firefox/i.test(navigator.userAgent);
4
5function sanitizeInlineQuotationOnCopy() {
6 // STRG+C, STRG+V on firefox leads to duplicate double quotes when inline quotation elements are copied.
7 // To work around this, take the selection and transform <q> to <span> before calling toString().
8 document.addEventListener('copy', function (event) {
9 const selection = window.getSelection();
10 if (!selection.anchorNode?.parentElement.closest('.mes_text')) {
11 return;
12 }
13
14 const range = selection.getRangeAt(0).cloneContents();
15 const tempDOM = document.createDocumentFragment();
16
17 function processNode(node) {
18 if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'q') {
19 // Transform <q> to <span>, preserve children
20 const span = document.createElement('span');
21
22 [...node.childNodes].forEach(child => {
23 const processedChild = processNode(child);
24 span.appendChild(processedChild);
25 });
26
27 return span;
28 } else {
29 // Nested structures containing <q> elements are unlikely
30 return node.cloneNode(true);
31 }
32 }
33
34 [...range.childNodes].forEach(child => {
35 const processedChild = processNode(child);
36 tempDOM.appendChild(processedChild);
37 });
38
39 const newRange = document.createRange();
40 newRange.selectNodeContents(tempDOM);
41
42 event.preventDefault();
43 event.clipboardData.setData('text/plain', newRange.toString());
44 });
45}
46
47function addSafariPatch() {
48 const userAgent = getParsedUA();
49 console.debug('User Agent', userAgent);
50 const isMobileSafari = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
51 const isDesktopSafari = userAgent?.browser?.name === 'Safari' && userAgent?.platform?.type === 'desktop';
52 const isIOS = userAgent?.os?.name === 'iOS';
53
54 if (isIOS || isMobileSafari || isDesktopSafari) {
55 document.body.classList.add('safari');
56 }
57}
58
59function applyBrowserFixes() {
60 if (isFirefox()) {
61 sanitizeInlineQuotationOnCopy();
62 }
63
64 if (isMobile()) {
65 const fixFunkyPositioning = () => {
66 console.debug('[Mobile] Device viewport change detected.');
67 document.documentElement.style.position = 'fixed';
68 requestAnimationFrame(() => document.documentElement.style.position = '');
69 };
70 window.addEventListener('resize', fixFunkyPositioning);
71 window.addEventListener('orientationchange', fixFunkyPositioning);
72 }
73
74 addSafariPatch();
75}
76
77export { isFirefox, applyBrowserFixes };