Blame Raw
Cohee · 51ad27fb · · 94 lines (3.5 KB)
2 contributors
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 if (document.activeElement instanceof HTMLInputElement || document.activeElement instanceof HTMLTextAreaElement) {
10 return;
11 }
12
13 const selection = window.getSelection();
14 if (!selection.anchorNode?.parentElement.closest('.mes_text')) {
15 return;
16 }
17
18 const range = selection.getRangeAt(0).cloneContents();
19 const tempDOM = document.createDocumentFragment();
20
21 /**
22 * Process a node, transforming <q> elements to <span> elements and preserving children.
23 * @param {Node} node Input node
24 * @returns {Node} Processed node
25 */
26 function processNode(node) {
27 if (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === 'q') {
28 // Transform <q> to <span>, preserve children
29 const span = document.createElement('span');
30
31 [...node.childNodes].forEach(child => {
32 const processedChild = processNode(child);
33 span.appendChild(processedChild);
34 });
35
36 return span;
37 } else {
38 // Nested structures containing <q> elements are unlikely
39 return node.cloneNode(true);
40 }
41 }
42
43 [...range.childNodes].forEach(child => {
44 const processedChild = processNode(child);
45 tempDOM.appendChild(processedChild);
46 });
47
48 const newRange = document.createRange();
49 newRange.selectNodeContents(tempDOM);
50
51 event.preventDefault();
52 event.clipboardData.setData('text/plain', newRange.toString());
53 });
54}
55
56function addSafariPatch() {
57 const userAgent = getParsedUA();
58 console.debug('User Agent', userAgent);
59 const isMobileSafari = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
60 const isDesktopSafari = userAgent?.browser?.name === 'Safari' && userAgent?.platform?.type === 'desktop';
61 const isIOS = userAgent?.os?.name === 'iOS';
62
63 if (isIOS || isMobileSafari || isDesktopSafari) {
64 document.body.classList.add('safari');
65 }
66}
67
68function applyBrowserFixes() {
69 if (isFirefox()) {
70 sanitizeInlineQuotationOnCopy();
71 }
72
73 if (isMobile()) {
74 const fixFunkyPositioning = () => {
75 if (isFirefox()) {
76 const active = document.activeElement;
77 if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) {
78 // The positioning hack below breaks GBoard candidate replacement
79 // in Firefox Mobile on Android.
80 return;
81 }
82 }
83 console.debug('[Mobile] Device viewport change detected.');
84 document.documentElement.style.position = 'fixed';
85 requestAnimationFrame(() => document.documentElement.style.position = '');
86 };
87 window.addEventListener('resize', fixFunkyPositioning);
88 window.addEventListener('orientationchange', fixFunkyPositioning);
89 }
90
91 addSafariPatch();
92}
93
94export { isFirefox, applyBrowserFixes };