Dynamically set text direction for Deepseek chat elements based on content
// ==UserScript==
// @name Dynamic DeepSeek RTL/LTR Direction
// @namespace http://tampermonkey.net/
// @version V4.2
// @description Dynamically set text direction for Deepseek chat elements based on content
// @author Reda Elsayed
// @match https://chat.deepseek.com/
// @match https://chat.deepseek.com/*
// @match https://chat.deepseek.com/*/chat/*/*
// @icon https://www.deepseek.com/path/to/icon.png
// @grant none
// ==/UserScript==
(function () {
"use strict";
// --- Selectors (update these if DeepSeek changes its class names again) ---
// Assistant markdown response container
// Old: "ds-markdown ds-markdown--block"
const ASSISTANT_MSG_SELECTOR = ".ds-markdown.ds-assistant-message-main-content";
// User message bubble
const USER_MSG_SELECTOR = ".fbb737a4";
// Code blocks (always force LTR)
const CODE_BLOCK_SELECTOR = ".md-code-block";
// Textarea (the input box)
// Old: "c92459f0" | New: "d96f2d2a"
const TEXTAREA_SELECTOR = "textarea.d96f2d2a, textarea.c92459f0";
// -------------------------------------------------------------------------
function isRTL(text) {
const rtlPattern = /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/;
return rtlPattern.test(text);
}
function applyDirection(element, text) {
if (!text || text.length === 0) return;
const dir = isRTL(text) ? "rtl" : "ltr";
if (element.style.direction !== dir) {
element.style.direction = dir;
element.style.textAlign = dir === "rtl" ? "right" : "left";
}
}
function updateDirection() {
// Assistant messages
document.querySelectorAll(ASSISTANT_MSG_SELECTOR).forEach((el) => {
applyDirection(el, el.textContent.trim());
});
// User messages
document.querySelectorAll(USER_MSG_SELECTOR).forEach((el) => {
applyDirection(el, el.textContent.trim());
});
// Code blocks — always LTR regardless of content
document.querySelectorAll(CODE_BLOCK_SELECTOR).forEach((el) => {
el.style.direction = "ltr";
el.style.textAlign = "left";
});
}
// Attach input-direction listener to a textarea element (idempotent)
const boundTextareas = new WeakSet();
function bindTextarea(textarea) {
if (boundTextareas.has(textarea)) return;
boundTextareas.add(textarea);
textarea.addEventListener("input", () => {
const text = textarea.value.trim();
const dir = isRTL(text) ? "rtl" : "ltr";
textarea.style.direction = dir;
textarea.style.textAlign = dir === "rtl" ? "right" : "left";
});
}
function bindAllTextareas() {
document.querySelectorAll(TEXTAREA_SELECTOR).forEach(bindTextarea);
}
function observeChanges() {
const observer = new MutationObserver(() => {
updateDirection();
bindAllTextareas(); // re-bind in case new textareas were injected
});
observer.observe(document.body, { childList: true, subtree: true });
}
// Initialize
updateDirection();
bindAllTextareas();
observeChanges();
})();