├── .github └── FUNDING.yml ├── chrome ├── assets │ ├── logo │ │ ├── 128.png │ │ ├── 16.png │ │ ├── 32.png │ │ └── 48.png │ ├── font │ │ ├── Vazirmatn-NL-Regular.ttf │ │ └── Vazirmatn-NL-Regular.woff2 │ └── screenshots │ │ ├── screenshot-1.png │ │ └── screenshot-2.png ├── src │ ├── background.js │ └── index.js └── manifest.json ├── firefox ├── assets │ ├── logo │ │ ├── 16.png │ │ ├── 32.png │ │ ├── 48.png │ │ └── 128.png │ ├── screenshots │ │ ├── screenshot-1.png │ │ └── screenshot-2.png │ └── font │ │ ├── Vazirmatn-NL-Regular.ttf │ │ └── Vazirmatn-NL-Regular.woff2 ├── src │ ├── background.js │ └── index.js └── manifest.json ├── .gitignore ├── release.sh ├── README.md └── LICENSE /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ["https://ashokri.com/donate/"] 2 | -------------------------------------------------------------------------------- /chrome/assets/logo/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/chrome/assets/logo/128.png -------------------------------------------------------------------------------- /chrome/assets/logo/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/chrome/assets/logo/16.png -------------------------------------------------------------------------------- /chrome/assets/logo/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/chrome/assets/logo/32.png -------------------------------------------------------------------------------- /chrome/assets/logo/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/chrome/assets/logo/48.png -------------------------------------------------------------------------------- /firefox/assets/logo/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/firefox/assets/logo/16.png -------------------------------------------------------------------------------- /firefox/assets/logo/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/firefox/assets/logo/32.png -------------------------------------------------------------------------------- /firefox/assets/logo/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/firefox/assets/logo/48.png -------------------------------------------------------------------------------- /firefox/assets/logo/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/firefox/assets/logo/128.png -------------------------------------------------------------------------------- /chrome/assets/font/Vazirmatn-NL-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/chrome/assets/font/Vazirmatn-NL-Regular.ttf -------------------------------------------------------------------------------- /chrome/assets/screenshots/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/chrome/assets/screenshots/screenshot-1.png -------------------------------------------------------------------------------- /chrome/assets/screenshots/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/chrome/assets/screenshots/screenshot-2.png -------------------------------------------------------------------------------- /firefox/assets/screenshots/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/firefox/assets/screenshots/screenshot-1.png -------------------------------------------------------------------------------- /firefox/assets/screenshots/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/firefox/assets/screenshots/screenshot-2.png -------------------------------------------------------------------------------- /chrome/assets/font/Vazirmatn-NL-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/chrome/assets/font/Vazirmatn-NL-Regular.woff2 -------------------------------------------------------------------------------- /firefox/assets/font/Vazirmatn-NL-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/firefox/assets/font/Vazirmatn-NL-Regular.ttf -------------------------------------------------------------------------------- /firefox/assets/font/Vazirmatn-NL-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirshnll/NotionFarsi-RTL/HEAD/firefox/assets/font/Vazirmatn-NL-Regular.woff2 -------------------------------------------------------------------------------- /chrome/src/background.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.onInstalled.addListener(() => { 2 | console.log("NotionFarsi-RTL Extension Installed."); 3 | }); 4 | 5 | // Handle toolbar icon click to open donation page 6 | chrome.action.onClicked.addListener(() => { 7 | chrome.tabs.create({ url: "https://ashokri.com/donate" }); 8 | }); 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | ._* 5 | node_modules/ 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | *.local 10 | *.env.local 11 | *.env.development.local 12 | *.env.test.local 13 | *.env.production.local 14 | .vscode/ 15 | .env 16 | *.pem 17 | *.key 18 | *.crt 19 | *.env 20 | .git/ -------------------------------------------------------------------------------- /firefox/src/background.js: -------------------------------------------------------------------------------- 1 | firefox.runtime.onInstalled.addListener(() => { 2 | console.log("NotionFarsi-RTL Extension Installed."); 3 | }); 4 | 5 | // Handle toolbar icon click to open donation page 6 | browser.browserAction.onClicked.addListener(() => { 7 | browser.tabs.create({ url: "https://ashokri.com/donate" }); 8 | }); 9 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | find . -type f -name ".DS_Store" -delete 2 | cd chrome 3 | zip -r chrome.zip . --exclude ".git/*" --exclude "release.sh" --exclude .DS_Store 4 | mv chrome.zip ~/Downloads/notion-chrome.zip 5 | cd .. 6 | cd firefox 7 | zip -r firefox.zip . --exclude ".git/*" --exclude "release.sh" --exclude .DS_Store 8 | mv firefox.zip ~/Downloads/notion-firefox.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NotionFarsi-RTL 2 | An extension to add RTL (Right-to-Left) support for Farsi in Notion. 3 | 4 | The RTL Notion Persian plugin is a user-friendly tool designed to enhance the experience of Persian and Arabic speakers within the Notion environment. Developed by Amir Shokri in collaboration with the Persian Notion Community, this open-source extension allows users to seamlessly align text, titles, and tables to the right, creating a layout optimized for right-to-left languages like Persian and Arabic. With this plugin, users can write, read, and manage their projects in Notion with improved readability and a more professional appearance. 5 | Key features of the plugin include automatic right alignment for text, headings, and tables, compatibility with Persian fonts for a polished display, and easy installation on popular browsers like Chrome and Firefox. Being open-source, the plugin ensures transparency, with its code publicly available for review. The RTL Notion Persian plugin transforms Notion into a more accessible and enjoyable workspace for right-to-left language users, promoting a streamlined and tailored experience. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Amir Shokri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /firefox/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NotionFarsi-RTL", 3 | "description": "An extension to add RTL (Right-to-Left) support for Farsi in Notion.", 4 | "version": "1.7.0", 5 | "manifest_version": 2, 6 | "icons": { 7 | "16": "assets/logo/16.png", 8 | "32": "assets/logo/32.png", 9 | "48": "assets/logo/48.png", 10 | "128": "assets/logo/128.png" 11 | }, 12 | "browser_action": { 13 | "default_icon": { 14 | "16": "assets/logo/16.png", 15 | "32": "assets/logo/32.png", 16 | "48": "assets/logo/48.png", 17 | "128": "assets/logo/128.png" 18 | }, 19 | "default_title": "NotionFarsi-RTL - Donate" 20 | }, 21 | "permissions": [ 22 | "*://*.notion.so/*", 23 | "*://*.notion.site/*", 24 | "*://*.notion.com/*", 25 | "*://*.api.notion.com/*", 26 | "*://*.img.notionusercontent.com/*", 27 | "*://*.notionusercontent.com/*", 28 | "*://*.secure.notion-static.com/*" 29 | ], 30 | "content_scripts": [ 31 | { 32 | "matches": [ 33 | "*://*.notion.so/*", 34 | "*://*.notion.site/*", 35 | "*://*.notion.com/*", 36 | "*://*.api.notion.com/*", 37 | "*://*.img.notionusercontent.com/*", 38 | "*://*.notionusercontent.com/*", 39 | "*://*.secure.notion-static.com/*" 40 | ], 41 | "js": [ 42 | "src/index.js" 43 | ], 44 | "run_at": "document_idle" 45 | } 46 | ], 47 | "background": { 48 | "scripts": [ 49 | "src/background.js" 50 | ], 51 | "persistent": true 52 | }, 53 | "web_accessible_resources": [ 54 | "assets/logo/16.png", 55 | "assets/logo/32.png", 56 | "assets/logo/48.png", 57 | "assets/logo/128.png", 58 | "assets/font/Vazirmatn-NL-Regular.ttf", 59 | "assets/font/Vazirmatn-NL-Regular.woff2" 60 | ] 61 | } -------------------------------------------------------------------------------- /chrome/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NotionFarsi-RTL", 3 | "description": "An extension to add RTL (Right-to-Left) support for Farsi in Notion.", 4 | "version": "1.7.0", 5 | "manifest_version": 3, 6 | "icons": { 7 | "16": "assets/logo/16.png", 8 | "32": "assets/logo/32.png", 9 | "48": "assets/logo/48.png", 10 | "128": "assets/logo/128.png" 11 | }, 12 | "action": { 13 | "default_icon": { 14 | "16": "assets/logo/16.png", 15 | "32": "assets/logo/32.png", 16 | "48": "assets/logo/48.png", 17 | "128": "assets/logo/128.png" 18 | }, 19 | "default_title": "NotionFarsi-RTL - Donate" 20 | }, 21 | "host_permissions": [ 22 | "*://*.notion.so/*", 23 | "*://*.notion.site/*", 24 | "*://*.notion.com/*", 25 | "*://*.api.notion.com/*", 26 | "*://*.img.notionusercontent.com/*", 27 | "*://*.notionusercontent.com/*", 28 | "*://*.secure.notion-static.com/*" 29 | ], 30 | "content_scripts": [ 31 | { 32 | "matches": [ 33 | "*://*.notion.so/*", 34 | "*://*.notion.site/*", 35 | "*://*.notion.com/*", 36 | "*://*.api.notion.com/*", 37 | "*://*.img.notionusercontent.com/*", 38 | "*://*.notionusercontent.com/*", 39 | "*://*.secure.notion-static.com/*" 40 | ], 41 | "js": [ 42 | "src/index.js" 43 | ], 44 | "run_at": "document_idle" 45 | } 46 | ], 47 | "background": { 48 | "service_worker": "src/background.js" 49 | }, 50 | "web_accessible_resources": [ 51 | { 52 | "resources": [ 53 | "assets/logo/16.png", 54 | "assets/logo/32.png", 55 | "assets/logo/48.png", 56 | "assets/logo/128.png", 57 | "assets/font/Vazirmatn-NL-Regular.ttf", 58 | "assets/font/Vazirmatn-NL-Regular.woff2" 59 | ], 60 | "matches": [ 61 | "*://*.notion.so/*", 62 | "*://*.notion.site/*" 63 | ] 64 | } 65 | ] 66 | } -------------------------------------------------------------------------------- /chrome/src/index.js: -------------------------------------------------------------------------------- 1 | const ROOT_LEVEL_CLASS_NAMES = [ 2 | "notion-page-content", 3 | "notion-table-view", 4 | "notion-board-view", 5 | "notion-gallery-view", 6 | "notion-page-block", 7 | "notion-topbar", 8 | "notion-body", 9 | "notion-selectable", 10 | "notion-collection_view-block", 11 | "notion-frame", 12 | "notion-collection-item", 13 | ]; 14 | const MUTATIONS_QUEUE = []; 15 | const CUSTOM_FONT_PATH = "assets/font/Vazirmatn-NL-Regular."; 16 | const WOFF2_FONT_PATH = chrome.runtime.getURL(CUSTOM_FONT_PATH + "woff2"); 17 | const TTF_FONT_PATH = chrome.runtime.getURL(CUSTOM_FONT_PATH + "ttf"); 18 | 19 | function injectCustomFontStyles() { 20 | const style = document.createElement("style"); 21 | style.textContent = ` 22 | @font-face { 23 | font-family: 'Vazirmatn NL'; 24 | src: url('${TTF_FONT_PATH}') format('truetype'), 25 | url('${WOFF2_FONT_PATH}') format('woff2'); 26 | font-weight: normal; 27 | font-style: normal; 28 | } 29 | .notion-page-content, .notion-table-view, .notion-board-view, 30 | .notion-gallery-view, .notion-page-block, .notion-topbar, .notion-body, 31 | .notion-body h1, .notion-body h2, .notion-body h3, .notion-body h4, .notion-body h5, .notion-body h6, 32 | .notion-body p, .notion-body span{ 33 | font-family: Vazirmatn NL, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol" !important; 34 | } 35 | .notion-collection_view-block div[data-content-editable-void="true"] > div:nth-child(2){ 36 | direction:rtl!important; 37 | } 38 | .notion-view-settings-sidebar { 39 | direction:ltr !important; 40 | } 41 | .notion-board-view{ 42 | float:none !important; 43 | } 44 | `; 45 | document.head.appendChild(style); 46 | } 47 | 48 | function applyCustomFontToElements() { 49 | const selector = ROOT_LEVEL_CLASS_NAMES.map( 50 | (className) => `.${className}` 51 | ).join(", "); 52 | const elements = document.querySelectorAll(selector); 53 | elements.forEach((element) => { 54 | element.style.setProperty( 55 | "font-family", 56 | "vazirmatn, sans-serif", 57 | "important" 58 | ); 59 | }); 60 | } 61 | 62 | function applyRTLToBlocks() { 63 | const bulletedListBlocks = document.querySelectorAll( 64 | ".notion-selectable.notion-bulleted_list-block" 65 | ); 66 | bulletedListBlocks.forEach((block) => { 67 | const rtlTextFound = /[\u0600-\u06FF]/.test(block.textContent); 68 | if (rtlTextFound) { 69 | block.setAttribute("dir", "rtl"); 70 | } 71 | }); 72 | 73 | const numberedListBlocks = document.querySelectorAll( 74 | ".notion-selectable.notion-numbered_list-block" 75 | ); 76 | numberedListBlocks.forEach((block) => { 77 | const rtlTextFound = /[\u0600-\u06FF]/.test(block.textContent); 78 | if (rtlTextFound) { 79 | block.setAttribute("dir", "rtl"); 80 | } 81 | }); 82 | 83 | const tableBlocks = document.querySelectorAll(".notion-table-block"); 84 | tableBlocks.forEach((block) => { 85 | const rtlTextFound = Array.from(block.querySelectorAll("*")).some((el) => 86 | /[\u0600-\u06FF]/.test(el.textContent) 87 | ); 88 | 89 | if (rtlTextFound) { 90 | block.setAttribute("dir", "rtl"); 91 | } 92 | }); 93 | 94 | const todoBlocks = document.querySelectorAll(".notion-to_do-block"); 95 | todoBlocks.forEach((block) => { 96 | const rtlTextFound = Array.from(block.querySelectorAll("*")).some((el) => 97 | /[\u0600-\u06FF]/.test(el.textContent) 98 | ); 99 | 100 | if (rtlTextFound) { 101 | block.setAttribute("dir", "rtl"); 102 | } 103 | }); 104 | } 105 | 106 | function initObservers() { 107 | const targetNode = document.body; 108 | 109 | const observer = new MutationObserver((mutations) => { 110 | mutations.forEach((mutation) => { 111 | const newNodes = [...mutation.addedNodes].filter( 112 | (n) => n.nodeType === Node.TEXT_NODE 113 | ); 114 | 115 | if (newNodes.length) { 116 | for (let node of newNodes) { 117 | const textContent = node.textContent; 118 | const parentTextContent = node.parentNode?.textContent || ''; 119 | const arabic = /[\u0600-\u06FF]/; 120 | 121 | if ((textContent && arabic.test(textContent)) || 122 | (parentTextContent && arabic.test(parentTextContent))) { 123 | node.parentNode.setAttribute("dir", "rtl"); 124 | } 125 | } 126 | } 127 | }); 128 | 129 | applyRTLToBlocks(); 130 | }); 131 | 132 | observer.observe(targetNode, { 133 | childList: true, 134 | subtree: true, 135 | }); 136 | } 137 | 138 | function init() { 139 | initObservers(); 140 | injectCustomFontStyles(); 141 | applyCustomFontToElements(); 142 | } 143 | 144 | init(); 145 | -------------------------------------------------------------------------------- /firefox/src/index.js: -------------------------------------------------------------------------------- 1 | const ROOT_LEVEL_CLASS_NAMES = [ 2 | "notion-page-content", 3 | "notion-table-view", 4 | "notion-board-view", 5 | "notion-gallery-view", 6 | "notion-page-block", 7 | "notion-topbar", 8 | "notion-body", 9 | "notion-selectable", 10 | "notion-collection_view-block", 11 | "notion-frame", 12 | "notion-collection-item", 13 | ]; 14 | const MUTATIONS_QUEUE = []; 15 | const CUSTOM_FONT_PATH = "assets/font/Vazirmatn-NL-Regular."; 16 | const WOFF2_FONT_PATH = browser.runtime.getURL(CUSTOM_FONT_PATH + "woff2"); 17 | const TTF_FONT_PATH = browser.runtime.getURL(CUSTOM_FONT_PATH + "ttf"); 18 | 19 | function injectCustomFontStyles() { 20 | const style = document.createElement("style"); 21 | style.textContent = ` 22 | @font-face { 23 | font-family: 'Vazirmatn NL'; 24 | src: url('${TTF_FONT_PATH}') format('truetype'), 25 | url('${WOFF2_FONT_PATH}') format('woff2'); 26 | font-weight: normal; 27 | font-style: normal; 28 | } 29 | .notion-page-content, .notion-table-view, .notion-board-view, 30 | .notion-gallery-view, .notion-page-block, .notion-topbar, .notion-body, 31 | .notion-body h1, .notion-body h2, .notion-body h3, .notion-body h4, .notion-body h5, .notion-body h6, 32 | .notion-body p, .notion-body span{ 33 | font-family: Vazirmatn NL, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol" !important; 34 | } 35 | .notion-collection_view-block div[data-content-editable-void="true"] > div:nth-child(2){ 36 | direction:rtl!important; 37 | } 38 | .notion-view-settings-sidebar { 39 | direction:ltr !important; 40 | } 41 | .notion-board-view{ 42 | float:none !important; 43 | } 44 | `; 45 | document.head.appendChild(style); 46 | } 47 | 48 | function applyCustomFontToElements() { 49 | const selector = ROOT_LEVEL_CLASS_NAMES.map( 50 | (className) => `.${className}` 51 | ).join(", "); 52 | const elements = document.querySelectorAll(selector); 53 | elements.forEach((element) => { 54 | element.style.setProperty( 55 | "font-family", 56 | "vazirmatn, sans-serif", 57 | "important" 58 | ); 59 | }); 60 | } 61 | 62 | function applyRTLToBlocks() { 63 | const bulletedListBlocks = document.querySelectorAll( 64 | ".notion-selectable.notion-bulleted_list-block" 65 | ); 66 | bulletedListBlocks.forEach((block) => { 67 | const rtlTextFound = /[\u0600-\u06FF]/.test(block.textContent); 68 | if (rtlTextFound) { 69 | block.setAttribute("dir", "rtl"); 70 | } 71 | }); 72 | 73 | const numberedListBlocks = document.querySelectorAll( 74 | ".notion-selectable.notion-numbered_list-block" 75 | ); 76 | numberedListBlocks.forEach((block) => { 77 | const rtlTextFound = /[\u0600-\u06FF]/.test(block.textContent); 78 | if (rtlTextFound) { 79 | block.setAttribute("dir", "rtl"); 80 | } 81 | }); 82 | 83 | const tableBlocks = document.querySelectorAll(".notion-table-block"); 84 | tableBlocks.forEach((block) => { 85 | const rtlTextFound = Array.from(block.querySelectorAll("*")).some((el) => 86 | /[\u0600-\u06FF]/.test(el.textContent) 87 | ); 88 | 89 | if (rtlTextFound) { 90 | block.setAttribute("dir", "rtl"); 91 | } 92 | }); 93 | 94 | const todoBlocks = document.querySelectorAll(".notion-to_do-block"); 95 | todoBlocks.forEach((block) => { 96 | const rtlTextFound = Array.from(block.querySelectorAll("*")).some((el) => 97 | /[\u0600-\u06FF]/.test(el.textContent) 98 | ); 99 | 100 | if (rtlTextFound) { 101 | block.setAttribute("dir", "rtl"); 102 | } 103 | }); 104 | } 105 | 106 | function initObservers() { 107 | const targetNode = document.body; 108 | 109 | const observer = new MutationObserver((mutations) => { 110 | mutations.forEach((mutation) => { 111 | const newNodes = [...mutation.addedNodes].filter( 112 | (n) => n.nodeType === Node.TEXT_NODE 113 | ); 114 | 115 | if (newNodes.length) { 116 | for (let node of newNodes) { 117 | const textContent = node.textContent; 118 | const parentTextContent = node.parentNode?.textContent || ''; 119 | const arabic = /[\u0600-\u06FF]/; 120 | 121 | if ((textContent && arabic.test(textContent)) || 122 | (parentTextContent && arabic.test(parentTextContent))) { 123 | node.parentNode.setAttribute("dir", "rtl"); 124 | } 125 | } 126 | } 127 | }); 128 | 129 | applyRTLToBlocks(); 130 | }); 131 | 132 | observer.observe(targetNode, { 133 | childList: true, 134 | subtree: true, 135 | }); 136 | } 137 | 138 | function init() { 139 | initObservers(); 140 | injectCustomFontStyles(); 141 | applyCustomFontToElements(); 142 | } 143 | 144 | init(); 145 | --------------------------------------------------------------------------------