diff --git a/cms/static/cms/js/modules/cms.modal.js b/cms/static/cms/js/modules/cms.modal.js index 7fe59a5def3..95e416d794b 100644 --- a/cms/static/cms/js/modules/cms.modal.js +++ b/cms/static/cms/js/modules/cms.modal.js @@ -576,6 +576,7 @@ class Modal { var height = this.ui.modal.height(); var modalLeft = this.ui.modal.position().left; var modalTop = this.ui.modal.position().top; + var resizeDir = this.ui.resize.css('direction') === 'rtl' ? -1 : +1; // create event for stopping this.ui.body.on(this.pointerUp, function(e) { @@ -588,11 +589,11 @@ class Modal { .on(this.pointerMove, function(e) { var mvX = pointerEvent.originalEvent.pageX - e.originalEvent.pageX; var mvY = pointerEvent.originalEvent.pageY - e.originalEvent.pageY; - var w = width - mvX * 2; + var w = width - resizeDir * mvX * 2; var h = height - mvY * 2; var wMin = that.options.minWidth; var hMin = that.options.minHeight; - var left = mvX + modalLeft; + var left = resizeDir * mvX + modalLeft; var top = mvY + modalTop; // add some limits diff --git a/cms/static/cms/sass/cms.base.scss b/cms/static/cms/sass/cms.base.scss index c252d30f52d..49ef9670b77 100644 --- a/cms/static/cms/sass/cms.base.scss +++ b/cms/static/cms/sass/cms.base.scss @@ -54,9 +54,7 @@ div.cms { @import "components/pagetree/node-state"; } -//############################################################################## -// DJANGO DEBUG TOOLBAR FIX -// removed as of: //github.com/divio/django-cms/issues/2476 -// #djDebug #djDebugToolbarHandle { -// top:35px !important; border-right:none !important; -// } + // Can be removed once suffucently many users have browsers the support `:dir()` +div.cms[dir=rtl] { + @import "libs/rtl_patch"; +} diff --git a/cms/static/cms/sass/cms.wizard.scss b/cms/static/cms/sass/cms.wizard.scss index 86d5862379a..e5d47badcf8 100644 --- a/cms/static/cms/sass/cms.wizard.scss +++ b/cms/static/cms/sass/cms.wizard.scss @@ -45,6 +45,9 @@ $wizard-input-size: 16px; // tablet and up @media (min-width: $screen-tablet) { float: left !important; + &:dir(rtl) { + float: right !important; + } width: 48% !important; } diff --git a/cms/static/cms/sass/components/_modal.scss b/cms/static/cms/sass/components/_modal.scss index e9093180f05..be423ab899f 100644 --- a/cms/static/cms/sass/components/_modal.scss +++ b/cms/static/cms/sass/components/_modal.scss @@ -193,7 +193,7 @@ .cms-modal-resize { position: absolute; - right: 0; + inset-inline-end: 0; bottom: 0; z-index: z(modal, resize); font-size: 10px; @@ -201,11 +201,17 @@ width: $modal-resize-size; height: $modal-resize-size; cursor: nw-resize; + &:dir(rtl) { + cursor: ne-resize; + } span { position: absolute; bottom: 5px; right: 5px; font-size: $font-size-small; + &:dir(rtl) { + transform: scale(-1,1) translate(2px, 0); // flip drag triangle + } } } @@ -256,6 +262,9 @@ $margin: math.div($toolbar-height - $toolbar-button-height, 2); @extend .cms-toolbar-item-buttons; float: right; + &:dir(rtl) { + float: left; + } margin-inline-start: $margin; .cancel-link { @@ -264,6 +273,9 @@ } .cms-modal-item-buttons-left { float: left; + &:dir(rtl) { + float: right; + } } // alter footer when html markup is loaded diff --git a/cms/static/cms/sass/components/_sideframe.scss b/cms/static/cms/sass/components/_sideframe.scss index 82f4f893f0d..d72bbe7e467 100644 --- a/cms/static/cms/sass/components/_sideframe.scss +++ b/cms/static/cms/sass/components/_sideframe.scss @@ -8,7 +8,7 @@ display: none; position: fixed; top: 0; - left: 0; + inline-start: 0; width: 0; bottom: 0; z-index: z(sideframe, base); @@ -60,7 +60,7 @@ .cms-sideframe-controls { position: absolute; top: $sideframe-buttons-position-top + $sideframe-buttons-offset; - right: $sideframe-buttons-position-right; + inset-inline-end: $sideframe-buttons-position-right; z-index: z(sideframe, buttons); box-shadow: $toolbar-shadow; background-color: $white; diff --git a/cms/static/cms/sass/components/_structureboard.scss b/cms/static/cms/sass/components/_structureboard.scss index 04aece4afe6..8a0300b31c3 100644 --- a/cms/static/cms/sass/components/_structureboard.scss +++ b/cms/static/cms/sass/components/_structureboard.scss @@ -17,12 +17,12 @@ content: ""; position: absolute; top: -8px; - left: -4px; + inset-inline-start: -4px; width: 0; height: 0; border-top: 8px solid transparent; border-bottom: 8px solid transparent; - border-left: 8px solid $color-primary; + border-inline-start: 8px solid $color-primary; } } .cms-draggables > .cms-droppable:first-child { @@ -371,7 +371,7 @@ margin-inline-start: $structure-dragarea-padding-horizontal - 10px; cursor: pointer; transform: rotate(180deg); - [dir="rtl"] & { + &:dir(rtl) { transform: rotate(0deg); } } @@ -381,7 +381,7 @@ } .cms-dragitem-expanded:before { transform: rotate(-90deg); - [dir="rtl"] & { + &:dir(rtl) { transform: rotate(-90deg); } } diff --git a/cms/static/cms/sass/components/_toolbar.scss b/cms/static/cms/sass/components/_toolbar.scss index dd4a2d6a9d0..aa35b4618c4 100644 --- a/cms/static/cms/sass/components/_toolbar.scss +++ b/cms/static/cms/sass/components/_toolbar.scss @@ -56,7 +56,7 @@ // items .cms-toolbar-item { float: left; - [dir=rtl] & { + &:dir(rtl) { float: right; } } @@ -85,7 +85,7 @@ z-index: 30; @at-root .cms-structure-mode-structure & { - right: $toolbar-height; + inset-inline-end: $toolbar-height; } } .cms-toolbar .cms-btn-action { @@ -107,13 +107,13 @@ li { position: relative; float: left; - [dir=rtl] & { + &:dir(rtl) { float: right; } } li a { float: left; - [dir=rtl] & { + &:dir(rtl) { float: right; } color: $toolbar-menu-item-color; @@ -184,7 +184,7 @@ display: block; .cms-icon { display: block; - [dir="rtl"] & { + &:dir(rtl) { // undo arrow rotation for RTL transform: rotate(0deg); } @@ -241,7 +241,7 @@ .cms-toolbar-item { float: none; - [dir=rtl] & { + [dir="rtl"] & { // a bit weird, but if removed, it will best match // with [dir="rtl"] div.cms .cms-toolbar .cms-toolbar-item // and will float to the right @@ -254,7 +254,7 @@ } .cms-toolbar-item-cms-mode-switcher a { float: left !important; - [dir=rtl] & { + &:dir(rtl) { float: right !important; } width: 50%; @@ -415,7 +415,7 @@ cursor: pointer; display: none; float: right; - [dir=rtl] & { + &:dir(rtl) { float: left; } position: relative; @@ -570,7 +570,7 @@ a { float: left; - [dir=rtl] & { + &:dir(rtl) { float: right; } line-height: $toolbar-button-height; diff --git a/cms/static/cms/sass/components/pagetree/_tree.scss b/cms/static/cms/sass/components/pagetree/_tree.scss index 18d0a73f570..e67d1542555 100644 --- a/cms/static/cms/sass/components/pagetree/_tree.scss +++ b/cms/static/cms/sass/components/pagetree/_tree.scss @@ -390,7 +390,7 @@ color: $gray-darkest; background: none; - [dir=rtl] & { + &:dir(rtl) { // inline-start & inline-end are not widely supported float: right; } @@ -451,7 +451,7 @@ min-width: $pagetree-cell-inner-height; height: $pagetree-cell-inner-height; - [dir=rtl] & { + &:dir(rtl) { // inline-start & inline-end are not widely supported float: left; } @@ -501,7 +501,7 @@ .cms-tree-reload { float: right; - [dir=rtl] & { + &:dir(rtl) { // inline-start & inline-end are not widely supported float: left; } @@ -652,7 +652,7 @@ float: left; margin-inline-end: 5px; - [dir=rtl] & { + &:dir(rtl) { // inline-start & inline-end are not widely supported float: right; } @@ -676,7 +676,7 @@ .cms-tree-filters { float: right; - [dir=rtl] & { + &:dir(rtl) { // inline-start & inline-end are not widely supported float: left; } @@ -822,7 +822,7 @@ margin-inline-start: -1px; } .jstree-ocl { - float: left; + float: left; position: relative; inset-inline-start: $pagetree-nesting-padding; font-size: 12px; @@ -832,7 +832,7 @@ padding-block-end: 10px; padding-inline-start: 0px; - [dir=rtl] & { + &:dir(rtl) { // inline-start & inline-end are not widely supported float: right; } @@ -892,7 +892,7 @@ color: $gray !important; } - [dir=rtl] & { + &:dir(rtl) { // no direct logical property for background-position background-position: calc(100% - 2px) center; } diff --git a/cms/static/cms/sass/libs/_rtl_patch.scss b/cms/static/cms/sass/libs/_rtl_patch.scss new file mode 100644 index 00000000000..e67e5395e27 --- /dev/null +++ b/cms/static/cms/sass/libs/_rtl_patch.scss @@ -0,0 +1,87 @@ +/* This patch file contains all :dir(rtl) selectors for browsers that do not support it yet */ +/* Once, sufficiently many users have browsers that support `:dir()`, this file can be removed */ + +/* component: toolbar */ + +.cms-toolbar { + .cms-toolbar-item { + float: right; + } +} + +.cms-toolbar-item-navigation { + li, li a { + float: right; + } + .cms-toolbar-item-navigation-children > a span .cms-icon { + transform: rotate(0deg); + } +} + +.cms-toolbar-more .cms-toolbar-item-cms-mode-switcher a { + float: right !important; +} + +.cms-messages .cms-messages-close { + float: left; +} + +.cms-toolbar-item-buttons a { + float: right; +} + + +/* component: modal */ + +.cms-modal-item-buttons { + float: left; +} + +.cms-modal-item-buttons-left { + float: right; +} + +.cms-modal-resize { + cursor: ne-resize; + span { + transform: scale(-1,1) translate(2px, 0); // flip drag triangle + } +} + + +/* component: structureboard */ + +.cms-structure { + .cms-dragitem-collapsable:before { + transform: rotate(0deg); + } + .cms-dragitem-expanded:before { + transform: rotate(-90deg); + } +} + + +/* component: tree */ + +.cms-pagetree-section { + h2 { + float: right; + } + +} + +.cms-tree-col, .cms-tree-reload, .cms-tree-filters { + float: left; +} + +.cms-tree-search { + float: right; +} + +.jstree-django-cms .jstree-ocl { + float: right; +} + +.jstree-anchor { + background-position: calc(100% - 2px) center; +} diff --git a/cms/static/cms/sass/settings/_cms.scss b/cms/static/cms/sass/settings/_cms.scss index 651b9d6d0f8..91a957fbd82 100644 --- a/cms/static/cms/sass/settings/_cms.scss +++ b/cms/static/cms/sass/settings/_cms.scss @@ -137,8 +137,8 @@ $z-layers: ( "messages": 999999, "toolbar": ( "base": 9999999, - "left": 10, - "right": 10, + "inset-inline-start": 10, + "inset-inline-end": 10, ), "sideframe": ( "base": 999999, diff --git a/cms/templates/cms/toolbar/toolbar.html b/cms/templates/cms/toolbar/toolbar.html index dac191103ca..1383f195e08 100644 --- a/cms/templates/cms/toolbar/toolbar.html +++ b/cms/templates/cms/toolbar/toolbar.html @@ -4,6 +4,8 @@ class="cms cms-reset {% if not user.is_authenticated %} cms-toolbar-auth{% endif %} {% if debug %} cms-toolbar-debug{% endif %}" + lang="{{ request.toolbar.toolbar_language }}" + dir="{{ request.toolbar.toolbar_language_bidi|yesno:'rtl,ltr,auto' }}" data-touch-action="none"> {% block toolbar_top %} diff --git a/cms/test_utils/testcases.py b/cms/test_utils/testcases.py index ddcef4407ef..a4d2d44d3cc 100644 --- a/cms/test_utils/testcases.py +++ b/cms/test_utils/testcases.py @@ -569,7 +569,7 @@ def get_page_change_template_uri(self, language, page): def get_add_plugin_uri(self, placeholder, plugin_type, language='en', parent=None, position=None): if placeholder.page: - path = placeholder.page.get_absolute_url(language) + path = placeholder.page.get_absolute_url(language) or f'/{language}/' else: path = f'/{language}/' @@ -593,7 +593,7 @@ def get_change_plugin_uri(self, plugin, language=None): language = language or 'en' if plugin.page: - path = plugin.page.get_absolute_url(language) + path = plugin.page.get_absolute_url(language) or f'/{language}/' else: path = f'/{language}/' @@ -605,7 +605,7 @@ def get_move_plugin_uri(self, plugin, language=None): language = language or 'en' if plugin.page: - path = plugin.page.get_absolute_url(language) + path = plugin.page.get_absolute_url(language) or f'/{language}/' else: path = f'/{language}/' @@ -617,7 +617,7 @@ def get_copy_plugin_uri(self, plugin, language=None): language = language or 'en' if plugin.page: - path = plugin.page.get_absolute_url(language) + path = plugin.page.get_absolute_url(language) or f'/{language}/' else: path = f'/{language}/' @@ -629,7 +629,7 @@ def get_copy_placeholder_uri(self, placeholder, language=None): language = language or 'en' if placeholder.page: - path = placeholder.page.get_absolute_url(language) + path = placeholder.page.get_absolute_url(language) or f'/{language}/' else: path = f'/{language}/' @@ -641,7 +641,7 @@ def get_delete_plugin_uri(self, plugin, language=None): language = language or 'en' if plugin.page: - path = plugin.page.get_absolute_url(language) + path = plugin.page.get_absolute_url(language) or f'/{language}/' else: path = f'/{language}/' @@ -653,7 +653,7 @@ def get_clear_placeholder_url(self, placeholder, language=None): language = language or 'en' if placeholder.page: - path = placeholder.page.get_absolute_url(language) + path = placeholder.page.get_absolute_url(language) or f'/{language}/' else: path = f'/{language}/' diff --git a/cms/toolbar/toolbar.py b/cms/toolbar/toolbar.py index 1daff29f411..1f69ebf7969 100644 --- a/cms/toolbar/toolbar.py +++ b/cms/toolbar/toolbar.py @@ -168,6 +168,7 @@ def __init__(self, request, request_path=None, _async=False): self.is_staff = None self.clipboard = None self.toolbar_language = None + self.toolbar_language_bidi = None self.show_toolbar = True self.init_toolbar(request, request_path=request_path) # Internal attribute to track whether we can cache @@ -252,6 +253,7 @@ def init_toolbar(self, request, request_path=None): user_settings.language = self.request_language user_settings.save() self.clipboard = user_settings.clipboard + self.toolbar_language_bidi = self.toolbar_language in settings.LANGUAGES_BIDI if hasattr(self, 'toolbars'): for key, toolbar in self.toolbars.items():