add sable-rtl fix script for tampermonkey ad-on
This commit is contained in:
@@ -0,0 +1,139 @@
|
|||||||
|
|
||||||
|
// ==UserScript==
|
||||||
|
// @name Sable RTL
|
||||||
|
// @author Amir Aref
|
||||||
|
// @version 0.1.0
|
||||||
|
// @description Fixes the direction of RTL languages in Sable Matrix Client
|
||||||
|
// @match https://cinny.khce.ir/*
|
||||||
|
// @match https://sable.khce.ir/*
|
||||||
|
// @grant none
|
||||||
|
// ==/UserScript==
|
||||||
|
|
||||||
|
|
||||||
|
// room meesages list timeline
|
||||||
|
// <div class="RoomTimeline_messageList__1n936q93">
|
||||||
|
|
||||||
|
|
||||||
|
; (function () {
|
||||||
|
"use strict";
|
||||||
|
const RTL_REGEX = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/;
|
||||||
|
const MESSAGE_LIST_SELECTORS = [
|
||||||
|
'[class*="RoomTimeline_messageList__"]'
|
||||||
|
];
|
||||||
|
const MESSAGE_ITEM_SELECTORS = [
|
||||||
|
'[class*="RoomMessage_message"]',
|
||||||
|
'[class*="layout_MessageBase__"]'
|
||||||
|
];
|
||||||
|
|
||||||
|
const styleId = 'sable-rtl-fix-style';
|
||||||
|
if (!document.getElementById(styleId)) {
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.id = styleId;
|
||||||
|
style.textContent = `
|
||||||
|
.sable-rtl-applied {
|
||||||
|
direction: rtl !important;
|
||||||
|
unicode-bidi: plaintext !important;
|
||||||
|
text-align: right !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesAnySelector(elem, selectors) {
|
||||||
|
if (!elem || !selectors.length) return false;
|
||||||
|
const combined = selectors.join(',');
|
||||||
|
return elem.matches(combined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closestSelector(elem, selectors) {
|
||||||
|
if (!elem || !selectors.length) return null;
|
||||||
|
const combined = selectors.join(',');
|
||||||
|
return elem.closest(combined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInMessageList(elem) {
|
||||||
|
return Boolean(closestSelector(elem, MESSAGE_LIST_SELECTORS));
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyRTLToElement(elem) {
|
||||||
|
if (!elem || elem.nodeType !== Node.ELEMENT_NODE) return;
|
||||||
|
if (elem.classList.contains('sable-rtl-applied')) return;
|
||||||
|
elem.classList.add('sable-rtl-applied');
|
||||||
|
elem.setAttribute('dir', 'auto');
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyRTLToTextNode(textNode) {
|
||||||
|
if (!textNode || textNode.nodeType !== Node.TEXT_NODE) return;
|
||||||
|
const elem = textNode.parentElement;
|
||||||
|
if (!elem) return;
|
||||||
|
if (!isInMessageList(elem)) return;
|
||||||
|
const txt = textNode.textContent || "";
|
||||||
|
if (RTL_REGEX.test(txt)) {
|
||||||
|
const messageItem = closestSelector(elem, MESSAGE_ITEM_SELECTORS);
|
||||||
|
if (messageItem) applyRTLToElement(messageItem);
|
||||||
|
applyRTLToElement(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyRTLToNode(node) {
|
||||||
|
if (!node) return;
|
||||||
|
if (node.nodeType === Node.TEXT_NODE) {
|
||||||
|
applyRTLToTextNode(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
||||||
|
const elem = node;
|
||||||
|
if (!isInMessageList(elem)) return;
|
||||||
|
const walker = document.createTreeWalker(elem, NodeFilter.SHOW_TEXT, null, false);
|
||||||
|
let cur;
|
||||||
|
while ((cur = walker.nextNode())) {
|
||||||
|
applyRTLToTextNode(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialScan(root) {
|
||||||
|
if (!root) root = document.body;
|
||||||
|
const messageLists = root.querySelectorAll(MESSAGE_LIST_SELECTORS.join(','));
|
||||||
|
if (!messageLists.length) return;
|
||||||
|
for (const list of messageLists) {
|
||||||
|
const walker = document.createTreeWalker(list, NodeFilter.SHOW_TEXT, null, false);
|
||||||
|
let cur;
|
||||||
|
while ((cur = walker.nextNode())) {
|
||||||
|
applyRTLToNode(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initialScan(document.body);
|
||||||
|
|
||||||
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
for (const mut of mutations) {
|
||||||
|
if (mut.type === 'childList') {
|
||||||
|
for (const nd of mut.addedNodes) {
|
||||||
|
if (nd.nodeType === Node.ELEMENT_NODE) {
|
||||||
|
const element = nd;
|
||||||
|
if (matchesAnySelector(element, MESSAGE_LIST_SELECTORS)) {
|
||||||
|
initialScan(element);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isInMessageList(element)) {
|
||||||
|
initialScan(element);
|
||||||
|
applyRTLToNode(element);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
applyRTLToNode(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mut.type === 'characterData') {
|
||||||
|
applyRTLToNode(mut.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
characterData: true
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user