29e3136473
This fixes the following bug in Firefox Mobile on Android:
**Steps to reproduce:**
1. Swipe a word into the chat input edit field in Firefox Mobile on Android, for examples "Test".
2. In GBoard (default Android keyboard), tap on a different suggestion, for examples "Rest".
**Expected behavior:** The word "Test" is replaced with "Rest".
**Actual behavior:** The word becomes "TestRest".
I confirmed with bisecting that the commit f897a4ab1a introduced the issue.
This change fixes the issue by disabling the layout hack while editing text.
Disabling the layout hack is limited to Firefox Mobile because
* I could not reproduce the bug in Chrome on Android
* This way, if it causes a new bug, only Firefox Mobile users are affected
95 lines
3.5 KiB
JavaScript
95 lines
3.5 KiB
JavaScript
import { getParsedUA, isMobile } from './RossAscends-mods.js';
|
|
|
|
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 <q> to <span> before calling toString().
|
|
document.addEventListener('copy', function (event) {
|
|
if (document.activeElement instanceof HTMLInputElement || document.activeElement instanceof HTMLTextAreaElement) {
|
|
return;
|
|
}
|
|
|
|
const selection = window.getSelection();
|
|
if (!selection.anchorNode?.parentElement.closest('.mes_text')) {
|
|
return;
|
|
}
|
|
|
|
const range = selection.getRangeAt(0).cloneContents();
|
|
const tempDOM = document.createDocumentFragment();
|
|
|
|
/**
|
|
* Process a node, transforming <q> elements to <span> elements and preserving children.
|
|
* @param {Node} node Input node
|
|
* @returns {Node} Processed node
|
|
*/
|
|
function processNode(node) {
|
|
if (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === 'q') {
|
|
// Transform <q> to <span>, preserve children
|
|
const span = document.createElement('span');
|
|
|
|
[...node.childNodes].forEach(child => {
|
|
const processedChild = processNode(child);
|
|
span.appendChild(processedChild);
|
|
});
|
|
|
|
return span;
|
|
} else {
|
|
// Nested structures containing <q> 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 addSafariPatch() {
|
|
const userAgent = getParsedUA();
|
|
console.debug('User Agent', userAgent);
|
|
const isMobileSafari = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
|
const isDesktopSafari = userAgent?.browser?.name === 'Safari' && userAgent?.platform?.type === 'desktop';
|
|
const isIOS = userAgent?.os?.name === 'iOS';
|
|
|
|
if (isIOS || isMobileSafari || isDesktopSafari) {
|
|
document.body.classList.add('safari');
|
|
}
|
|
}
|
|
|
|
function applyBrowserFixes() {
|
|
if (isFirefox()) {
|
|
sanitizeInlineQuotationOnCopy();
|
|
}
|
|
|
|
if (isMobile()) {
|
|
const fixFunkyPositioning = () => {
|
|
if (isFirefox()) {
|
|
const active = document.activeElement;
|
|
if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) {
|
|
// The positioning hack below breaks GBoard candidate replacement
|
|
// in Firefox Mobile on Android.
|
|
return;
|
|
}
|
|
}
|
|
console.debug('[Mobile] Device viewport change detected.');
|
|
document.documentElement.style.position = 'fixed';
|
|
requestAnimationFrame(() => document.documentElement.style.position = '');
|
|
};
|
|
window.addEventListener('resize', fixFunkyPositioning);
|
|
window.addEventListener('orientationchange', fixFunkyPositioning);
|
|
}
|
|
|
|
addSafariPatch();
|
|
}
|
|
|
|
export { isFirefox, applyBrowserFixes };
|