Support RTL language direction
- Use bootstrap-rtl-ondemand css rules to modify bootstrap behavior. - Add flip class on navbar. - Switch offcanavas direction. - Replace right/left icon depending. - Flip icon image issue7388 review74291002
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Support RTL language direction
|
||||
* Apply factor on domain parser
|
||||
* Use tab name in CSV Export/Import
|
||||
* Add bus management
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@
|
||||
"c3": "^0.6",
|
||||
"papaparse": "^4.1",
|
||||
"fullcalendar": "^3.0",
|
||||
"mousetrap": "^1.6"
|
||||
"mousetrap": "^1.6",
|
||||
"bootstrap-rtl-ondemand": "^3.3.4-ondemand"
|
||||
},
|
||||
"devDependencies": {
|
||||
"qunit": "^1.18"
|
||||
|
||||
+4
-3
@@ -23,6 +23,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<script type="text/javascript" src="bower_components/mousetrap/mousetrap.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="bower_components/bootstrap-rtl-ondemand/dist/css/bootstrap-rtl-ondemand.min.css">
|
||||
<link rel="stylesheet" href="bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css">
|
||||
<link rel="stylesheet" href="bower_components/c3/c3.min.css">
|
||||
<link rel="stylesheet" href="bower_components/fullcalendar/dist/fullcalendar.min.css">
|
||||
@@ -53,9 +54,9 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="main_navbar">
|
||||
<form class="navbar-form navbar-left" role="search" id="global-search">
|
||||
<form class="navbar-form navbar-left flip" role="search" id="global-search">
|
||||
</form>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<ul class="nav navbar-nav navbar-right flip">
|
||||
<li id="user-preferences"></li>
|
||||
<li id="user-logout"></li>
|
||||
</ul>
|
||||
@@ -67,7 +68,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<div id="main" class="container-fluid" style="padding: 0px;">
|
||||
<div class="row row-offcanvas row-offcanvas-left active"
|
||||
style="height: calc(100vh - 50px - 1px - 20px); margin: 0px;">
|
||||
<div class="col-xs-6 col-sm-3 col-lg-2 sidebar-offcanvas" id="menu" role="navigation"
|
||||
<div class="col-xs-12 col-sm-3 col-lg-2 sidebar-offcanvas" id="menu" role="navigation"
|
||||
style="overflow-y: auto; height: 100%;"></div>
|
||||
<div class="col-xs-12 col-md-9 col-lg-10 main-offcanvas" style="overflow-y: auto; height: 100%;">
|
||||
<div id="tabs" role="tabpanel">
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ body {
|
||||
}
|
||||
|
||||
.sidebar-offcanvas {
|
||||
position: absolute;
|
||||
position: absolute !important;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -280,6 +280,13 @@ var Sao = {};
|
||||
Sao.i18n.BC47 = function(lang) {
|
||||
return lang.replace('_', '-');
|
||||
};
|
||||
Sao.i18n.set_direction = function(direction) {
|
||||
Sao.i18n.rtl = (direction === 'rtl');
|
||||
jQuery('html').attr('dir', direction);
|
||||
jQuery('.row-offcanvas')
|
||||
.removeClass('row-offcanvas-left row-offcanvas-right')
|
||||
.addClass(Sao.i18n.rtl ? 'row-offcanvas-right' : 'row-offcanvas-left');
|
||||
};
|
||||
Sao.i18n.locale = {};
|
||||
|
||||
Sao.get_preferences = function() {
|
||||
@@ -311,6 +318,7 @@ var Sao = {};
|
||||
}
|
||||
prm.resolve(preferences);
|
||||
});
|
||||
Sao.i18n.set_direction(preferences.language_direction);
|
||||
Sao.i18n.locale = preferences.locale;
|
||||
return prm;
|
||||
});
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
display: block;
|
||||
margin-right: 15px;
|
||||
}
|
||||
[dir="rtl"] & > span {
|
||||
margin-right: 0;
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
#menu, #tabs {
|
||||
@@ -21,13 +25,22 @@
|
||||
#menu {
|
||||
border-right: 2px solid @table-border-color;
|
||||
}
|
||||
[dir="rtl"] #menu {
|
||||
border-right: none;
|
||||
border-left: 2px solid @table-border-color;
|
||||
}
|
||||
@media screen and (max-width: @screen-sm-max) {
|
||||
#menu {
|
||||
border-right: none;
|
||||
border-left: none;
|
||||
}
|
||||
.active #menu {
|
||||
border-right: 2px solid @table-border-color;
|
||||
}
|
||||
[dir="rtl"] .active #menu {
|
||||
border-right: none;
|
||||
border-left: 2px solid @table-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
#user-preferences > a {
|
||||
@@ -118,6 +131,9 @@ input[type='color'] {
|
||||
img.icon {
|
||||
height: unit(@line-height-base, em);
|
||||
}
|
||||
[dir="rtl"] img.icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.filter-box {
|
||||
margin: 5px 5px;
|
||||
@@ -149,9 +165,11 @@ img.icon {
|
||||
&.char, &.text, &.many2one, &.one2one, &.date, &.time, &.selection,
|
||||
&.reference, &.url, &.email, &.callto, &.sip {
|
||||
text-align: left;
|
||||
text-align: start;
|
||||
}
|
||||
&.timedelta, &.float, &.numeric, &.integer, &.biginteger {
|
||||
text-align: right;
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
& > tbody > tr > td {
|
||||
@@ -164,9 +182,17 @@ img.icon {
|
||||
& td.prefix {
|
||||
padding-right: @table-cell-padding;
|
||||
}
|
||||
[dir="rtl"] & td.prefix {
|
||||
padding-right: 0;
|
||||
padding-left: @table-cell-padding;
|
||||
}
|
||||
& td.suffix {
|
||||
padding-left: @table-cell-padding;
|
||||
}
|
||||
[dir="rtl"] & td.suffix {
|
||||
padding-left: 0;
|
||||
padding-right: @table-cell-padding;
|
||||
}
|
||||
& img.column-affix, a.column-affix > img {
|
||||
width: unit(@line-height-base, em);
|
||||
height: unit(@line-height-base, em);
|
||||
@@ -210,6 +236,10 @@ img.icon {
|
||||
margin-right: 5px;
|
||||
width: 1em;
|
||||
}
|
||||
[dir="rtl"] & > img {
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
& label {
|
||||
font-weight: normal;
|
||||
@@ -279,6 +309,9 @@ img.icon {
|
||||
float: left;
|
||||
margin: 5px;
|
||||
}
|
||||
[dir="rtl"] & .form-one2many-string, .form-many2many-string {
|
||||
float: right;
|
||||
}
|
||||
& .form-one2many-toolbar, .form-many2many-toolbar {
|
||||
display: inline-table;
|
||||
float: right;
|
||||
@@ -290,6 +323,9 @@ img.icon {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
[dir="rtl"] & .form-one2many-toolbar, .form-many2many-toolbar {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
& .form-one2many-content, .form-many2many-content {
|
||||
& .treeview {
|
||||
@@ -351,10 +387,12 @@ img.icon {
|
||||
.editabletree-integer, .editabletree-float, .editabletree-timedelta {
|
||||
& input {
|
||||
text-align: right;
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
.column-integer, .column-float, .column-timedelta {
|
||||
text-align: right;
|
||||
text-align: end;
|
||||
}
|
||||
.column-many2many, .column-one2many {
|
||||
text-align: center;
|
||||
@@ -371,6 +409,7 @@ input.column-boolean {
|
||||
|
||||
.dict-label {
|
||||
text-align: right;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
@@ -385,6 +424,7 @@ input.column-boolean {
|
||||
.window-form {
|
||||
& .window-form-toolbar {
|
||||
text-align: right;
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,6 +440,7 @@ input.column-boolean {
|
||||
@media screen and (max-width: @screen-xs-max) {
|
||||
.dict-label {
|
||||
text-align: left;
|
||||
text-align: start;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,6 +467,7 @@ input.column-boolean {
|
||||
& > thead > tr,
|
||||
& > tbody > tr > td {
|
||||
text-align: left !important;
|
||||
text-align: start !important;
|
||||
/* Force height to empty content */
|
||||
& > span:empty {
|
||||
min-height: 20px;
|
||||
@@ -466,11 +508,18 @@ input.column-boolean {
|
||||
left: 6px;
|
||||
padding-right: 10px;
|
||||
text-align: left;
|
||||
text-align: start;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
/* Label */
|
||||
content: attr(data-title);
|
||||
}
|
||||
[dir="rtl"] & > td:before {
|
||||
padding-right: 0;
|
||||
padding-left: 10px;
|
||||
left: unset;
|
||||
right: 6px;
|
||||
}
|
||||
& > td.required:before {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
+2
-2
@@ -161,7 +161,7 @@
|
||||
}).append(jQuery('<div/>', {
|
||||
'class': 'container-fluid'
|
||||
}).append(jQuery('<div/>', {
|
||||
'class': 'dropdown navbar-header navbar-left'
|
||||
'class': 'dropdown navbar-header navbar-left flip'
|
||||
}).append(jQuery('<a/>', {
|
||||
'href': "#",
|
||||
'class': "navbar-brand dropdown-toggle",
|
||||
@@ -185,7 +185,7 @@
|
||||
}).append('×')).click(function() {
|
||||
this.close();
|
||||
}.bind(this)))).append(jQuery('<div/>', {
|
||||
'class': 'btn-toolbar navbar-right',
|
||||
'class': 'btn-toolbar navbar-right flip',
|
||||
'role': 'toolbar'
|
||||
})));
|
||||
var wrapper = jQuery('<div/>', {
|
||||
|
||||
+22
-6
@@ -20,18 +20,34 @@
|
||||
if (this.attributes.mode == 'week') {
|
||||
defaultview = this.get_week_view();
|
||||
}
|
||||
var header = {
|
||||
left: 'today prev,next',
|
||||
center: 'title',
|
||||
right: 'month,' + this.get_week_view(),
|
||||
};
|
||||
if (Sao.i18n.rtl) {
|
||||
var header_rtl = jQuery.extend({}, header);
|
||||
header_rtl.left = header.right;
|
||||
header_rtl.right = header.left;
|
||||
header = header_rtl;
|
||||
}
|
||||
this.el.fullCalendar({
|
||||
defaultView: defaultview,
|
||||
header: {
|
||||
left: 'prev,next',
|
||||
center: 'title',
|
||||
right: ' month,' + this.get_week_view()
|
||||
},
|
||||
header: header,
|
||||
timeFormat: 'H:mm',
|
||||
events: this.get_events.bind(this),
|
||||
locale: lang,
|
||||
buttonIcons: false,
|
||||
isRTL: Sao.i18n.rtl,
|
||||
themeSystem: 'bootstrap3',
|
||||
bootstrapGlyphicons: {
|
||||
'prev': 'chevron-' + (Sao.i18n.rtl? 'right' : 'left'),
|
||||
'next': 'chevron-' + (Sao.i18n.rtl? 'left' : 'right'),
|
||||
},
|
||||
buttonTextOverride: {
|
||||
'today': Sao.i18n.gettext("Today"),
|
||||
'month': Sao.i18n.gettext("Month"),
|
||||
'week': Sao.i18n.gettext("Week"),
|
||||
},
|
||||
eventRender: this.event_render.bind(this),
|
||||
eventResize: this.event_resize.bind(this),
|
||||
eventDrop: this.event_drop.bind(this),
|
||||
|
||||
+14
-6
@@ -157,7 +157,6 @@ function eval_pyson(value){
|
||||
attributes.states = model.fields[name].description.states;
|
||||
}
|
||||
if (attributes.string === undefined) {
|
||||
// TODO RTL and translation
|
||||
attributes.string = model.fields[name]
|
||||
.description.string + ': ';
|
||||
}
|
||||
@@ -544,7 +543,13 @@ function eval_pyson(value){
|
||||
|
||||
if (attributes.xalign !== undefined) {
|
||||
// TODO replace by start/end when supported
|
||||
cell.css('text-align', attributes.xalign >= 0.5? 'right': 'left');
|
||||
var align;
|
||||
if (Sao.i18n.rtl) {
|
||||
align = attributes.xalign >= 0.5? 'left': 'right';
|
||||
} else {
|
||||
align = attributes.xalign >= 0.5? 'right': 'left';
|
||||
}
|
||||
cell.css('text-align', align);
|
||||
}
|
||||
if (xexpand) {
|
||||
cell.addClass('xexpand');
|
||||
@@ -2008,13 +2013,13 @@ function eval_pyson(value){
|
||||
add_buttons([
|
||||
{
|
||||
'icon': 'align-left',
|
||||
'command': 'justifyLeft'
|
||||
'command': Sao.i18n.rtl? 'justifyRight' : 'justifyLeft',
|
||||
}, {
|
||||
'icon': 'align-center',
|
||||
'command': 'justifyCenter'
|
||||
}, {
|
||||
'icon': 'align-right',
|
||||
'command': 'justifyRight'
|
||||
'command': Sao.i18n.rtl? 'justifyLeft': 'justifyRight',
|
||||
}, {
|
||||
'icon': 'align-justify',
|
||||
'command': 'justifyFull'
|
||||
@@ -2087,7 +2092,11 @@ function eval_pyson(value){
|
||||
}
|
||||
// Some browsers set start as default align
|
||||
if (el.attr('align') == 'start') {
|
||||
el.attr('align', 'left');
|
||||
if (Sao.i18n.rtl) {
|
||||
el.attr('align', 'right');
|
||||
} else {
|
||||
el.attr('align', 'left');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -4127,7 +4136,6 @@ function eval_pyson(value){
|
||||
this.rows[key] = row = jQuery('<div/>', {
|
||||
'class': 'row'
|
||||
});
|
||||
// TODO RTL
|
||||
var text = key_schema.string + Sao.i18n.gettext(':');
|
||||
var label = jQuery('<label/>', {
|
||||
'text': text
|
||||
|
||||
+7
-4
@@ -250,7 +250,6 @@
|
||||
if (!attributes.sum) {
|
||||
return;
|
||||
}
|
||||
// TODO RTL
|
||||
var label = attributes.sum + Sao.i18n.gettext(': ');
|
||||
var sum = jQuery('<label/>', {
|
||||
'text': label,
|
||||
@@ -875,7 +874,6 @@
|
||||
for (var i = 0; i < this.tree.columns.length; i++) {
|
||||
var column = this.tree.columns[i];
|
||||
td = jQuery('<td/>', {
|
||||
// TODO RTL
|
||||
'data-title': column.attributes.string + Sao.i18n.gettext(': ')
|
||||
}).append(jQuery('<span/>', { // For responsive min-height
|
||||
'aria-hidden': true
|
||||
@@ -898,10 +896,15 @@
|
||||
td.append(table);
|
||||
if ((i === 0) && this.children_field) {
|
||||
this.expander = jQuery('<img/>', {
|
||||
'tabindex': 0
|
||||
'tabindex': 0,
|
||||
'class': 'icon',
|
||||
});
|
||||
this.expander.html(' ');
|
||||
this.expander.css('margin-left', (depth - 1) + 'em');
|
||||
var margin = 'margin-left';
|
||||
if (Sao.i18n.rtl) {
|
||||
margin = 'margin-right';
|
||||
}
|
||||
this.expander.css(margin, (depth - 1) + 'em');
|
||||
this.expander.on('click keypress',
|
||||
Sao.common.click_press(this.toggle_row.bind(this)));
|
||||
row.append(jQuery('<td/>', {
|
||||
|
||||
Reference in New Issue
Block a user