Skip to content

Commit f513fdd

Browse files
ImangazalievMneSpeccgohaberegtasuku-sathul7744
authored
Add RTL support (#1248)
* [Improvements] ESLint action (#1099) * TSLint -> ESLint, GitHub Action * Update eslint.yml * Autofix * more autofix * fix * manually fix some issues * Update CHANGELOG.md * [Refactor] ESLint fixed (#1100) Co-authored-by: Peter Savchenko <specc.dev@gmail.com> * [Feature] i18n (#1106) * i18n first steps * i18n internal, toolbox, api for tools * namespaced api * tn, t * tn in block tunes * join toolbox and inlineTools under toolNames * translations * make enum toolTypes * Update block.ts * Update src/components/core.ts Co-Authored-By: George Berezhnoy <gohabereg@users.noreply.github.com> * add more types * rm tn * export i18n types * upd bundle * fix tabulation * Add type-safe namespaces * upd * Improve example * Update toolbox.ts * improve examplle * upd * fix typo * Add comments for complex types Co-authored-by: George Berezhnoy <gohabereg@users.noreply.github.com> Co-authored-by: Georgy Berezhnoy <gohabereg@gmail.com> * Remove unused submodule * Fixed: icon centering in Firefox * Do not load styles twice (#1112) * Do not load styles twice * Add changelog * Fix issue link Co-authored-by: Peter Savchenko <specc.dev@gmail.com> * Show warning if Block to delete is not found (#1111) Resolves #1102 * Save Tools' order in the Toolbox (#1113) Resolves #1073 * fix $.isEmpty performance (#1096) * fix $.isEmpty performance * add changelog * upd bundle Co-authored-by: Peter Savchenko <specc.dev@gmail.com> * Add issue templates (#1114) * Update issue templates (#1121) * Update issue templates * Apply suggestions from code review Co-Authored-By: George Berezhnoy <gohabereg@users.noreply.github.com> * upd texts * Update feature_request.md * Update .github/ISSUE_TEMPLATE/discussion.md Co-Authored-By: George Berezhnoy <gohabereg@users.noreply.github.com> Co-authored-by: George Berezhnoy <gohabereg@users.noreply.github.com> * Allowing deleting block by block id (#1108) * Allowing deleting block by block id * Fixed no argument error * Making index value optional for delete operation * Added to changelog * Making index value optional for delete operation * Added parameter description * Update docs/CHANGELOG.md * Update types/api/blocks.d.ts * Update editor.js Co-authored-by: Peter Savchenko <specc.dev@gmail.com> * Allow navigate next from last non-initial block (#1110) Resolves #1103 * Create CODE_OF_CONDUCT.md (#1171) * Create CODE_OF_CONDUCT.md * Update changelog file * Update dependencies (#1122) * Update dependencies * upd codex.tooltip * Update editor.js.LICENSE.txt Co-authored-by: Peter Savchenko <specc.dev@gmail.com> * Feature/disable tab event config (#1164) * Highlight first block on autofocus (#1127) * Fix shortcut for external tools (#1141) * fix/shortcut-for-external-tools * Check inline tools property for shortcut Co-authored-by: George Berezhnoy <gohabereg@gmail.com> * Hotfix/issue1133 selection shortcut removed on editor destroy (#1140) * Removed shortcut CMD+A on editor destroy #1133 * Removed patch version and made code cleaner #1133 * lint error fixes #1133 Co-authored-by: Sisir <sisir@hellosivi.com> Co-authored-by: George Berezhnoy <gohabereg@gmail.com> * [Feature] BlockAPI Interface (#1075) * Fix BlockManager.insert method (#1172) * Fix BlockManager.insert method * upd * Explicitly check for undefined * Update tools master branches (#1180) * Update master branches * Update image * Update CHANGELOG.md * Fix behaviour of inputs editing in block settings (#1123) * lint code * Update CHANGELOG.md * Added RTL support * Fixed code style * Fixed icons positioning in the toolbar in the RTL mode * Renamed example-dev-rtl.html to example-rtl.html * Moved 'direction' option to 'i18n' section * Fixed an issue with arrow navigation between blocks * Renamed rtl-fix to codex-editor--rtl * Fixed icons positioning in the narrow mode for RTL * Replaced 'isRtl' method with getter * Fixed bug with the editor initialization when 'i18n' option is not set * narrow mode improved * Changelog added Co-authored-by: Peter Savchenko <specc.dev@gmail.com> Co-authored-by: George Berezhnoy <gohabereg@users.noreply.github.com> Co-authored-by: Georgy Berezhnoy <gohabereg@gmail.com> Co-authored-by: tasuku-s <tasuku@freemind.co.jp> Co-authored-by: Athul Anil Kumar <athul7744@outlook.com> Co-authored-by: Taly <vitalik7tv@yandex.ru> Co-authored-by: flaming-cl <51183663+flaming-cl@users.noreply.github.com> Co-authored-by: Nguyen Ngoc Son <sonnn.se@gmail.com> Co-authored-by: Sisir Das K <37764463+sis-dk@users.noreply.github.com> Co-authored-by: Sisir <sisir@hellosivi.com> Co-authored-by: ImangazalievM <mahach.miangazaliev@gmail.com>
1 parent cdb48c4 commit f513fdd

File tree

13 files changed

+379
-15
lines changed

13 files changed

+379
-15
lines changed

dist/editor.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### 2.19
44

5+
- `New` - RTL mode added [#670](https://github.com/codex-team/editor.js/issues/670)
56
- `Fix` — Fix problem with types usage [#1183](https://github.com/codex-team/editor.js/issues/1183)
67
- `Fix` - Fixed issue with Spam clicking the "Click to tune" button duplicates the icons on FireFox. [#1273](https://github.com/codex-team/editor.js/issues/1273)
78
- `Fix` - Fixed issue with `editor.blocks.delete(index)` method which throws an error when Editor.js is not focused, even after providing a valid index. [#1182](https://github.com/codex-team/editor.js/issues/1182)

example/example-rtl.html

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
<!--
2+
Use this page for debugging purposes.
3+
Editor Tools are loaded as git-submodules.
4+
You can pull modules by running `yarn pull_tools` and start experimenting.
5+
-->
6+
<!DOCTYPE html>
7+
<html lang="en">
8+
<head>
9+
<meta charset="UTF-8">
10+
<title>Editor.js 🤩🧦🤨 example</title>
11+
<link href="https://fonts.googleapis.com/css?family=PT+Mono" rel="stylesheet">
12+
<link href="assets/demo.css" rel="stylesheet">
13+
<script src="assets/json-preview.js"></script>
14+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
15+
</head>
16+
<body>
17+
<div class="ce-example">
18+
<div class="ce-example__header">
19+
<a class="ce-example__header-logo" href="https://codex.so/editor">Editor.js 🤩🧦🤨</a>
20+
21+
<div class="ce-example__header-menu">
22+
<a href="https://github.com/editor-js" target="_blank">Plugins</a>
23+
<a href="https://editorjs.io/usage" target="_blank">Usage</a>
24+
<a href="https://editorjs.io/configuration" target="_blank">Configuration</a>
25+
<a href="https://editorjs.io/creating-a-block-tool" target="_blank">API</a>
26+
</div>
27+
</div>
28+
<div class="ce-example__content _ce-example__content--small">
29+
<div id="editorjs"></div>
30+
<div id="hint" style="text-align: center;">
31+
No submodules found. Run <code class="inline-code">yarn pull_tools</code>
32+
</div>
33+
<div class="ce-example__button" id="saveButton">
34+
editor.save()
35+
</div>
36+
</div>
37+
<div class="ce-example__output">
38+
<pre class="ce-example__output-content" id="output"></pre>
39+
40+
<div class="ce-example__output-footer">
41+
<a href="https://codex.so" style="font-weight: bold;">Made by CodeX</a>
42+
</div>
43+
</div>
44+
</div>
45+
46+
<!-- Load Tools -->
47+
<!--
48+
You can upload Tools to your project's directory and use as in example below.
49+
Also you can load each Tool from CDN or use NPM/Yarn packages.
50+
Read more in Tool's README file. For example:
51+
https://github.com/editor-js/header#installation
52+
-->
53+
<script src="./tools/header/dist/bundle.js" onload="document.getElementById('hint').hidden = true"></script><!-- Header -->
54+
<script src="./tools/simple-image/dist/bundle.js"></script><!-- Image -->
55+
<script src="./tools/delimiter/dist/bundle.js"></script><!-- Delimiter -->
56+
<script src="./tools/list/dist/bundle.js"></script><!-- List -->
57+
<script src="./tools/checklist/dist/bundle.js"></script><!-- Checklist -->
58+
<script src="./tools/quote/dist/bundle.js"></script><!-- Quote -->
59+
<script src="./tools/code/dist/bundle.js"></script><!-- Code -->
60+
<script src="./tools/embed/dist/bundle.js"></script><!-- Embed -->
61+
<script src="./tools/table/dist/bundle.js"></script><!-- Table -->
62+
<script src="./tools/link/dist/bundle.js"></script><!-- Link -->
63+
<script src="./tools/raw/dist/bundle.js"></script><!-- Raw -->
64+
<script src="./tools/warning/dist/bundle.js"></script><!-- Warning -->
65+
66+
<script src="./tools/marker/dist/bundle.js"></script><!-- Marker -->
67+
<script src="./tools/inline-code/dist/bundle.js"></script><!-- Inline Code -->
68+
69+
<!-- Load Editor.js's Core -->
70+
<script src="../dist/editor.js"></script>
71+
72+
<!-- Initialization -->
73+
<script>
74+
/**
75+
* Saving button
76+
*/
77+
const saveButton = document.getElementById('saveButton');
78+
79+
/**
80+
* To initialize the Editor, create a new instance with configuration object
81+
* @see docs/installation.md for mode details
82+
*/
83+
var editor = new EditorJS({
84+
/**
85+
* Wrapper of Editor
86+
*/
87+
holder: 'editorjs',
88+
i18n: {
89+
90+
/**
91+
* Text direction
92+
*/
93+
direction: 'rtl',
94+
},
95+
96+
/**
97+
* Tools list
98+
*/
99+
tools: {
100+
/**
101+
* Each Tool is a Plugin. Pass them via 'class' option with necessary settings {@link docs/tools.md}
102+
*/
103+
header: {
104+
class: Header,
105+
inlineToolbar: ['link'],
106+
config: {
107+
placeholder: 'Header'
108+
},
109+
shortcut: 'CMD+SHIFT+H'
110+
},
111+
112+
/**
113+
* Or pass class directly without any configuration
114+
*/
115+
image: {
116+
class: SimpleImage,
117+
inlineToolbar: ['link'],
118+
},
119+
120+
list: {
121+
class: List,
122+
inlineToolbar: true,
123+
shortcut: 'CMD+SHIFT+L'
124+
},
125+
126+
checklist: {
127+
class: Checklist,
128+
inlineToolbar: true,
129+
},
130+
131+
quote: {
132+
class: Quote,
133+
inlineToolbar: true,
134+
config: {
135+
quotePlaceholder: 'Enter a quote',
136+
captionPlaceholder: 'Quote\'s author',
137+
},
138+
shortcut: 'CMD+SHIFT+O'
139+
},
140+
141+
warning: Warning,
142+
143+
marker: {
144+
class: Marker,
145+
shortcut: 'CMD+SHIFT+M'
146+
},
147+
148+
code: {
149+
class: CodeTool,
150+
shortcut: 'CMD+SHIFT+C'
151+
},
152+
153+
delimiter: Delimiter,
154+
155+
inlineCode: {
156+
class: InlineCode,
157+
shortcut: 'CMD+SHIFT+C'
158+
},
159+
160+
linkTool: LinkTool,
161+
162+
raw: RawTool,
163+
164+
embed: Embed,
165+
166+
table: {
167+
class: Table,
168+
inlineToolbar: true,
169+
shortcut: 'CMD+ALT+T'
170+
},
171+
172+
},
173+
174+
/**
175+
* This Tool will be used as default
176+
*/
177+
// initialBlock: 'paragraph',
178+
179+
/**
180+
* Initial Editor data
181+
*/
182+
data: {
183+
blocks: [
184+
{
185+
type: "header",
186+
data: {
187+
text: "محرر.js",
188+
level: 2
189+
}
190+
},
191+
{
192+
type : 'paragraph',
193+
data : {
194+
text : 'مرحبا! تعرف على المحرر الجديد. في هذه الصفحة ، يمكنك رؤيتها في العمل - حاول تحرير هذا النص.'
195+
}
196+
},
197+
{
198+
type: "header",
199+
data: {
200+
text: "دلائل الميزات",
201+
level: 3
202+
}
203+
},
204+
{
205+
type : 'list',
206+
data : {
207+
items : [
208+
'وهو محرر بنمط الكتلة',
209+
'تقوم بإرجاع إخراج بيانات نظيفة في JSON',
210+
'مصممة لتكون قابلة للتوسيع والتوصيل مع واجهة برمجة تطبيقات بسيطة'
211+
],
212+
style: 'unordered'
213+
}
214+
}
215+
]
216+
},
217+
onReady: function(){
218+
saveButton.click();
219+
},
220+
onChange: function() {
221+
console.log('something changed');
222+
}
223+
});
224+
225+
/**
226+
* Saving example
227+
*/
228+
saveButton.addEventListener('click', function () {
229+
editor.save().then((savedData) => {
230+
cPreview.show(savedData, document.getElementById("output"));
231+
});
232+
});
233+
</script>
234+
</body>
235+
</html>

src/components/__module.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,12 @@ export default class Module {
4646
public set state(Editor: EditorModules) {
4747
this.Editor = Editor;
4848
}
49+
50+
/**
51+
* Returns true if current direction is RTL (Right-To-Left)
52+
*/
53+
protected get isRtl(): boolean {
54+
return this.config.i18n.direction === 'rtl';
55+
}
56+
4957
}

src/components/core.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,18 @@ export default class Core {
210210
/**
211211
* Adjust i18n
212212
*/
213-
if (config.i18n && config.i18n.messages) {
213+
if (config.i18n?.messages) {
214214
I18n.setDictionary(config.i18n.messages);
215215
}
216+
217+
/**
218+
* Text direction. If not set, uses ltr
219+
*/
220+
if (config.i18n?.direction) {
221+
this.config.i18n = {
222+
direction: config.i18n?.direction || 'ltr',
223+
};
224+
}
216225
}
217226

218227
/**

src/components/modules/blockEvents.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,10 @@ export default class BlockEvents extends Module {
426426
return;
427427
}
428428

429-
if (this.Editor.Caret.navigateNext()) {
429+
const navigateNext = event.keyCode === _.keyCodes.UP || (event.keyCode === _.keyCodes.RIGHT && !this.isRtl);
430+
const isNavigated = navigateNext ? this.Editor.Caret.navigateNext() : this.Editor.Caret.navigatePrevious();
431+
432+
if (isNavigated) {
430433
/**
431434
* Default behaviour moves cursor by 1 character, we need to prevent it
432435
*/
@@ -481,7 +484,10 @@ export default class BlockEvents extends Module {
481484
return;
482485
}
483486

484-
if (this.Editor.Caret.navigatePrevious()) {
487+
const navigatePrevious = event.keyCode === _.keyCodes.UP || (event.keyCode === _.keyCodes.LEFT && !this.isRtl);
488+
const isNavigated = navigatePrevious ? this.Editor.Caret.navigatePrevious() : this.Editor.Caret.navigateNext();
489+
490+
if (isNavigated) {
485491
/**
486492
* Default behaviour moves cursor by 1 character, we need to prevent it
487493
*/

src/components/modules/toolbar/conversion.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ export default class ConversionToolbar extends Module {
6565
* Create UI of Conversion Toolbar
6666
*/
6767
public make(): HTMLElement {
68-
this.nodes.wrapper = $.make('div', ConversionToolbar.CSS.conversionToolbarWrapper);
68+
this.nodes.wrapper = $.make('div', [
69+
ConversionToolbar.CSS.conversionToolbarWrapper,
70+
...(this.isRtl ? [this.Editor.UI.CSS.editorRtlFix] : []),
71+
]);
6972
this.nodes.tools = $.make('div', ConversionToolbar.CSS.conversionToolbarTools);
7073

7174
const label = $.make('div', ConversionToolbar.CSS.conversionToolbarLabel, {
@@ -158,7 +161,7 @@ export default class ConversionToolbar extends Module {
158161
*
159162
* @param {string} replacingToolName - name of Tool which replaces current
160163
*/
161-
public async replaceWithBlock(replacingToolName: string): Promise <void> {
164+
public async replaceWithBlock(replacingToolName: string): Promise<void> {
162165
/**
163166
* At first, we get current Block data
164167
*
@@ -295,8 +298,8 @@ export default class ConversionToolbar extends Module {
295298
* @param {string} title - button title
296299
*/
297300
private addTool(toolName: string, toolIcon: string, title: string): void {
298-
const tool = $.make('div', [ ConversionToolbar.CSS.conversionTool ]);
299-
const icon = $.make('div', [ ConversionToolbar.CSS.conversionToolIcon ]);
301+
const tool = $.make('div', [ConversionToolbar.CSS.conversionTool]);
302+
const icon = $.make('div', [ConversionToolbar.CSS.conversionToolIcon]);
300303

301304
tool.dataset.tool = toolName;
302305
icon.innerHTML = toolIcon;
@@ -307,7 +310,7 @@ export default class ConversionToolbar extends Module {
307310
$.append(this.nodes.tools, tool);
308311
this.tools[toolName] = tool;
309312

310-
this.Editor.Listeners.on(tool, 'click', async () => {
313+
this.Editor.Listeners.on(tool, 'click', async() => {
311314
await this.replaceWithBlock(toolName);
312315
});
313316
}

src/components/modules/toolbar/inline.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default class InlineToolbar extends Module {
3232
focusedButton: 'ce-inline-tool--focused',
3333
conversionToggler: 'ce-inline-toolbar__dropdown',
3434
conversionTogglerHidden: 'ce-inline-toolbar__dropdown--hidden',
35-
conversionTogglerContent: 'ce-inline-toolbar__dropdown-content',
35+
conversionTogglerContent: 'ce-inline-toolbar__dropdown-content'
3636
};
3737

3838
/**
@@ -116,7 +116,10 @@ export default class InlineToolbar extends Module {
116116
* Making DOM
117117
*/
118118
public make(): void {
119-
this.nodes.wrapper = $.make('div', this.CSS.inlineToolbar);
119+
this.nodes.wrapper = $.make('div', [
120+
this.CSS.inlineToolbar,
121+
...(this.isRtl ? [this.Editor.UI.CSS.editorRtlFix] : []),
122+
]);
120123
this.nodes.buttons = $.make('div', this.CSS.buttonsWrapper);
121124
this.nodes.actions = $.make('div', this.CSS.actionsWrapper);
122125

@@ -569,7 +572,7 @@ export default class InlineToolbar extends Module {
569572

570573
return (toolClass as ToolSettings).class[Tools.INTERNAL_SETTINGS.IS_INLINE];
571574
})
572-
.map(([ name ]: [string, InlineToolConstructable | ToolSettings]) => name);
575+
.map(([name]: [string, InlineToolConstructable | ToolSettings]) => name);
573576

574577
/**
575578
* 1) For internal tools, check public getter 'shortcut'

0 commit comments

Comments
 (0)