mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Added base RTL support
For #939 - Adds way to check if current language is RTL via config system. - Made TinyMCE default direction be based on current language text direction. - Fixed bullet points to be RTL compatible. - Set page content body to have direction based on content.
This commit is contained in:
parent
c667c6e235
commit
1cb6ae39c8
@ -6,6 +6,9 @@ use Illuminate\Http\Request;
|
|||||||
|
|
||||||
class Localization
|
class Localization
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected $rtlLocales = ['ar'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
*
|
||||||
@ -23,6 +26,11 @@ class Localization
|
|||||||
$locale = setting()->getUser(user(), 'language', $defaultLang);
|
$locale = setting()->getUser(user(), 'language', $defaultLang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set text direction
|
||||||
|
if (in_array($locale, $this->rtlLocales)) {
|
||||||
|
config()->set('app.rtl', true);
|
||||||
|
}
|
||||||
|
|
||||||
app()->setLocale($locale);
|
app()->setLocale($locale);
|
||||||
Carbon::setLocale($locale);
|
Carbon::setLocale($locale);
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
@ -79,6 +79,19 @@ return [
|
|||||||
'locale' => env('APP_LANG', 'en'),
|
'locale' => env('APP_LANG', 'en'),
|
||||||
'locales' => ['en', 'ar', 'de', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'sv', 'ja', 'pl', 'it', 'ru', 'zh_CN', 'zh_TW'],
|
'locales' => ['en', 'ar', 'de', 'es', 'es_AR', 'fr', 'nl', 'pt_BR', 'sk', 'sv', 'ja', 'pl', 'it', 'ru', 'zh_CN', 'zh_TW'],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Right-to-left text control
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Right-to-left text control is set to false by default since English
|
||||||
|
| is the primary supported application but this may be dynamically
|
||||||
|
| altered by the applications localization system.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'rtl' => false,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Auto-detect the locale for public users
|
| Auto-detect the locale for public users
|
||||||
|
@ -8,6 +8,7 @@ class MarkdownEditor {
|
|||||||
|
|
||||||
constructor(elem) {
|
constructor(elem) {
|
||||||
this.elem = elem;
|
this.elem = elem;
|
||||||
|
this.textDirection = document.getElementById('page-editor').getAttribute('text-direction');
|
||||||
this.markdown = new MarkdownIt({html: true});
|
this.markdown = new MarkdownIt({html: true});
|
||||||
this.markdown.use(mdTasksLists, {label: true});
|
this.markdown.use(mdTasksLists, {label: true});
|
||||||
|
|
||||||
@ -98,6 +99,9 @@ class MarkdownEditor {
|
|||||||
|
|
||||||
codeMirrorSetup() {
|
codeMirrorSetup() {
|
||||||
let cm = this.cm;
|
let cm = this.cm;
|
||||||
|
// Text direction
|
||||||
|
// cm.setOption('direction', this.textDirection);
|
||||||
|
cm.setOption('direction', 'ltr'); // Will force to remain as ltr for now due to issues when HTML is in editor.
|
||||||
// Custom key commands
|
// Custom key commands
|
||||||
let metaKey = code.getMetaKey();
|
let metaKey = code.getMetaKey();
|
||||||
const extraKeys = {};
|
const extraKeys = {};
|
||||||
|
@ -370,6 +370,7 @@ class WysiwygEditor {
|
|||||||
|
|
||||||
constructor(elem) {
|
constructor(elem) {
|
||||||
this.elem = elem;
|
this.elem = elem;
|
||||||
|
this.textDirection = document.getElementById('page-editor').getAttribute('text-direction');
|
||||||
|
|
||||||
this.plugins = "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor media";
|
this.plugins = "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor media";
|
||||||
this.loadPlugins();
|
this.loadPlugins();
|
||||||
@ -385,6 +386,14 @@ class WysiwygEditor {
|
|||||||
drawIoPlugin();
|
drawIoPlugin();
|
||||||
this.plugins += ' drawio';
|
this.plugins += ' drawio';
|
||||||
}
|
}
|
||||||
|
if (this.textDirection === 'rtl') {
|
||||||
|
this.plugins += ' directionality'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getToolBar() {
|
||||||
|
const textDirPlugins = this.textDirection === 'rtl' ? 'ltr rtl' : '';
|
||||||
|
return `undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr drawio media | removeformat code ${textDirPlugins} fullscreen`
|
||||||
}
|
}
|
||||||
|
|
||||||
getTinyMceConfig() {
|
getTinyMceConfig() {
|
||||||
@ -397,6 +406,7 @@ class WysiwygEditor {
|
|||||||
body_class: 'page-content',
|
body_class: 'page-content',
|
||||||
browser_spellcheck: true,
|
browser_spellcheck: true,
|
||||||
relative_urls: false,
|
relative_urls: false,
|
||||||
|
directionality : this.textDirection,
|
||||||
remove_script_host: false,
|
remove_script_host: false,
|
||||||
document_base_url: window.baseUrl('/'),
|
document_base_url: window.baseUrl('/'),
|
||||||
statusbar: false,
|
statusbar: false,
|
||||||
@ -407,7 +417,7 @@ class WysiwygEditor {
|
|||||||
valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote],+div[pre],+div[img]",
|
valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote],+div[pre],+div[img]",
|
||||||
plugins: this.plugins,
|
plugins: this.plugins,
|
||||||
imagetools_toolbar: 'imageoptions',
|
imagetools_toolbar: 'imageoptions',
|
||||||
toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr drawio media | removeformat code fullscreen",
|
toolbar: this.getToolBar(),
|
||||||
content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
|
content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
|
||||||
style_formats: [
|
style_formats: [
|
||||||
{title: "Header Large", format: "h2"},
|
{title: "Header Large", format: "h2"},
|
||||||
|
@ -157,6 +157,7 @@ function wysiwygView(elem) {
|
|||||||
|
|
||||||
newWrap.className = 'CodeMirrorContainer';
|
newWrap.className = 'CodeMirrorContainer';
|
||||||
newWrap.setAttribute('data-lang', lang);
|
newWrap.setAttribute('data-lang', lang);
|
||||||
|
newWrap.setAttribute('dir', 'ltr');
|
||||||
newTextArea.style.display = 'none';
|
newTextArea.style.display = 'none';
|
||||||
elem.parentNode.replaceChild(newWrap, elem);
|
elem.parentNode.replaceChild(newWrap, elem);
|
||||||
|
|
||||||
|
@ -351,6 +351,7 @@ ul, ol {
|
|||||||
}
|
}
|
||||||
ul {
|
ul {
|
||||||
padding-left: $-m * 1.3;
|
padding-left: $-m * 1.3;
|
||||||
|
padding-right: $-m * 1.3;
|
||||||
list-style: disc;
|
list-style: disc;
|
||||||
ul {
|
ul {
|
||||||
list-style: circle;
|
list-style: circle;
|
||||||
@ -365,6 +366,7 @@ ul {
|
|||||||
ol {
|
ol {
|
||||||
list-style: decimal;
|
list-style: decimal;
|
||||||
padding-left: $-m * 2;
|
padding-left: $-m * 2;
|
||||||
|
padding-right: $-m * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
li.checkbox-item, li.task-list-item {
|
li.checkbox-item, li.task-list-item {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
drawio-enabled="{{ config('services.drawio') ? 'true' : 'false' }}"
|
drawio-enabled="{{ config('services.drawio') ? 'true' : 'false' }}"
|
||||||
editor-type="{{ setting('app-editor') }}"
|
editor-type="{{ setting('app-editor') }}"
|
||||||
page-id="{{ $model->id or 0 }}"
|
page-id="{{ $model->id or 0 }}"
|
||||||
|
text-direction="{{ config('app.rtl') ? 'rtl' : 'ltr' }}"
|
||||||
page-new-draft="{{ $model->draft or 0 }}"
|
page-new-draft="{{ $model->draft or 0 }}"
|
||||||
page-update-draft="{{ $model->isDraft or 0 }}">
|
page-update-draft="{{ $model->isDraft or 0 }}">
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div>
|
<div dir="auto">
|
||||||
|
|
||||||
<h1 class="break-text" v-pre id="bkmrk-page-title">{{$page->name}}</h1>
|
<h1 class="break-text" v-pre id="bkmrk-page-title">{{$page->name}}</h1>
|
||||||
|
|
||||||
|
@ -72,4 +72,13 @@ class LanguageTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_rtl_config_set_if_lang_is_rtl()
|
||||||
|
{
|
||||||
|
$this->asEditor();
|
||||||
|
$this->assertFalse(config('app.rtl'), "App RTL config should be false by default");
|
||||||
|
setting()->putUser($this->getEditor(), 'language', 'ar');
|
||||||
|
$this->get('/');
|
||||||
|
$this->assertTrue(config('app.rtl'), "App RTL config should have been set to true by middleware");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user