Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prevent child changing parent element dir #79

Merged
merged 1 commit into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 20 additions & 18 deletions AutoDirPostProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MarkdownPostProcessorContext } from 'obsidian';
import { Direction, detectDirection } from "globals";
import { Direction, detectDirection } from './globals';

let lastDetectedDir: Direction = 'ltr';

Expand Down Expand Up @@ -29,8 +29,8 @@ function breaksToDivs(el: HTMLElement) {

// Try to detect if the postprocessor was asked to run inside a canvas element, and in that case, use the
// supplied setPreviewDirection function to launch the plugin logic and set the text to the file's direction.
function detectCanvasElement(el: HTMLElement, ctx: MarkdownPostProcessorContext, setPreviewDirection: SetPreviewDirection) {
const container = (ctx as any).containerEl as HTMLElement;
function detectCanvasElement(ctx: MarkdownPostProcessorContext, setPreviewDirection: SetPreviewDirection) {
const container = ctx ? (ctx as any).containerEl as HTMLElement : null;
if (container && container.closest) {
const possibleCanvas = container.closest('.canvas-node-content');
if (possibleCanvas) {
Expand Down Expand Up @@ -65,8 +65,7 @@ export const autoDirectionPostProcessor = (
setPreviewDirection: SetPreviewDirection,
) => {
let shouldAddDir = false, addedDir = false;
detectCanvasElement(el, ctx, setPreviewDirection);
detectExport(el, ctx, setPreviewDirection);
detectCanvasElement(ctx, setPreviewDirection);

// Obsidian renders adjacent lines as one <p> element with <br> breaks. Since these cannot
// be set a direction individually, the following breaks them into individual divs.
Expand All @@ -79,15 +78,17 @@ export const autoDirectionPostProcessor = (
if (dir) {
addedDir = true;
lastDetectedDir = dir;
if (specialNodes.contains(el.nodeName) && el.parentElement) {
if (specialNodes.includes(el.nodeName) && el.parentElement) {
let target = nonSpecialParent(el.parentElement);
if (target != null) {
addDirClassIfNotAddedBefore(target, dirClass(dir));
if (target &&
/* If parent (target) has text with strong direction before this special node then don't change the parent direction */
!(target.childNodes.length !== 0 && target.childNodes[0].nodeValue && detectDirection(target.childNodes[0].nodeValue))) {
addDirClass(target, dirClass(dir));
}
} else {
addDirClassIfNotAddedBefore(el, dirClass(dir));
addDirClass(el, dirClass(dir));
if (el.parentElement && el.parentElement.nodeName === 'LI') {
addDirClassIfNotAddedBefore(el.parentElement, dirClass(dir));
addDirClass(el.parentElement, dirClass(dir));
}
}
}
Expand All @@ -99,14 +100,14 @@ export const autoDirectionPostProcessor = (
autoDirectionPostProcessor(n as HTMLElement, ctx, setPreviewDirection);

if (i === el.childNodes.length - 1 && shouldAddDir && !addedDir) {
el.addClass(dirClass(lastDetectedDir));
el.classList.add(dirClass(lastDetectedDir));
}
}

if (el.nodeName === "UL") {
const lis = el.querySelectorAll('li');
if (lis.length > 0 && lis[0].hasClass('esm-rtl')) {
el.addClass(dirClass('rtl'));
if (lis.length > 0 && lis[0].classList.contains('esm-rtl')) {
el.classList.add(dirClass('rtl'));
}
}
}
Expand All @@ -119,15 +120,16 @@ function dirClass(dir: Direction): string {
}
}

function addDirClassIfNotAddedBefore(el: HTMLElement, cls: string) {
if (!el.hasClass(cls)) {
el.removeClass('esm-rtl', 'esm-ltr');
el.addClass(cls);
function addDirClass(el: HTMLElement, cls: string) {
if (el.classList.contains(cls)) {
return;
}
el.classList.remove('esm-rtl', 'esm-ltr');
el.classList.add(cls);
}

function nonSpecialParent(el: HTMLElement) {
while (specialNodes.contains(el.nodeName)) {
while (specialNodes.includes(el.nodeName)) {
el = el.parentElement;
}

Expand Down
8 changes: 8 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
transform: {'^.+\\.ts?$': 'ts-jest'},
// testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'mjs', 'node']
};
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json"
"version": "node version-bump.mjs && git add manifest.json versions.json",
"test": "jest"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@codemirror/view": "^6.7.3",
"@jest/globals": "^29.7.0",
"@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0",
"codemirror": "^6.0.1",
"esbuild": "0.14.47",
"jest-environment-jsdom": "^29.7.0",
"obsidian": "latest",
"prettier": "^2.7.1",
"ts-jest": "^29.1.2",
"tslib": "2.4.0",
"typescript": "4.7.4"
}
Expand Down
36 changes: 36 additions & 0 deletions tests/AutoDirPostProcessor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { describe, expect, test } from "@jest/globals";
import { autoDirectionPostProcessor } from "../AutoDirPostProcessor";

describe("AutoDirPostProcessor", () => {
test("special node should not change parent element direction if there is text with decidable direction before", () => {
const rtlHTML = convertToHTMLElement(
`<div><p>سلام، <em>Hello</em></p></div>`,
);
autoDirectionPostProcessor(rtlHTML, null, null);
expect(rtlHTML.outerHTML).toBe(
`<div><p class="esm-rtl">سلام، <em>Hello</em></p></div>`,
);

const ltrHTML = convertToHTMLElement(
`<div><p>Hello, <em>سلام</em></p></div>`,
);
autoDirectionPostProcessor(ltrHTML, null, null);
expect(ltrHTML.outerHTML).toBe(
`<div><p class="esm-ltr">Hello, <em>سلام</em></p></div>`,
);
});

test("special node should change parent element direction if there isn't text with decidable direction before", () => {
const html = convertToHTMLElement(`<div><p>[<em>سلام</em></p>]</div>`);
autoDirectionPostProcessor(html, null, null);
expect(html.outerHTML).toBe(
`<div><p class="esm-rtl">[<em>سلام</em></p>]</div>`,
);
});
});

function convertToHTMLElement(str: string): HTMLElement {
const template = document.createElement("template");
template.innerHTML = str;
return template.content.firstChild as HTMLElement;
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"esModuleInterop": true,
"lib": [
"dom",
"DOM.Iterable",
"DOM.Iterable",
"es6",
"scripthost",
"es2015"
Expand Down