summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorAaron Bohy <aab@odoo.com>2019-03-18 14:51:04 +0000
committerAaron Bohy <aab@odoo.com>2019-04-02 11:55:57 +0000
commit9fbb4fb44ff92cdee53454ab328c10ae66a11aa0 (patch)
tree5fd611cbf41a582951250558ff1055ffe9fba9fe /addons/web/static/src
parenta75fa7e377829ac22f85eab3bfefd79705458236 (diff)
[IMP] web: editable list: table-layout: fixed
This rev. changes the layout of *editable* list views to a fixed layout. This means that we are now responsible of the width of each column. To do that, we associate with each field type a factor, and the higher the factor is, the larger the column will be (w.r.t. the others). This default value can be overriden in the arch. The fixed layout allows to remove the absolute positionning of widgets inside editable lists (done in the next commit). Part of task 1915702 Co-authored-by: Martin Geubelle <mge@odoo.com>
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js3
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js1
-rw-r--r--addons/web/static/src/js/views/list/list_editable_renderer.js87
-rw-r--r--addons/web/static/src/js/views/list/list_renderer.js13
-rw-r--r--addons/web/static/src/scss/list_view.scss24
5 files changed, 116 insertions, 12 deletions
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index 4940839e612..1c5c19ebcf8 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -444,7 +444,6 @@ var FieldChar = InputField.extend(TranslatableFieldMixin, {
},
});
-
var LinkButton = AbstractField.extend({
events: _.extend({}, AbstractField.prototype.events, {
'click': '_onClick'
@@ -483,7 +482,6 @@ var LinkButton = AbstractField.extend({
event.stopPropagation();
window.open(this.value, '_blank');
},
-
});
var FieldDate = InputField.extend({
@@ -1164,6 +1162,7 @@ var FieldText = InputField.extend(TranslatableFieldMixin, {
*/
var HandleWidget = AbstractField.extend({
className: 'o_row_handle fa fa-arrows ui-sortable-handle',
+ widthFactor: 0,
tagName: 'span',
description: "",
supportedFieldTypes: ['integer'],
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index 7be77cedca0..0f247ba3a8d 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -766,6 +766,7 @@ var FieldMany2One = AbstractField.extend({
});
var ListFieldMany2One = FieldMany2One.extend({
+
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js
index 9e31a188922..687f046b7e6 100644
--- a/addons/web/static/src/js/views/list/list_editable_renderer.js
+++ b/addons/web/static/src/js/views/list/list_editable_renderer.js
@@ -447,6 +447,41 @@ ListRenderer.include({
}
},
/**
+ * Returns the relative width according to the widget or the field type.
+ * @see _renderHeader
+ *
+ * @param {Object} column a `field` arch node
+ */
+ _getColumnWidthFactor: function (column) {
+ if (column.attrs.width) {
+ // the width attribute has precedence on the width factor
+ return 0;
+ }
+ var fieldType = this.state.fields[column.attrs.name].type;
+ var widget = this.state.fieldsInfo.list[column.attrs.name].Widget.prototype;
+ if ('widthFactor' in widget) {
+ return widget.widthFactor;
+ }
+ switch (fieldType) {
+ case 'binary': return 1;
+ case 'boolean': return 0.4;
+ case 'char': return 1;
+ case 'date': return 1;
+ case 'datetime': return 1.5;
+ case 'float': return 1;
+ case 'html': return 3;
+ case 'integer': return 0.8;
+ case 'many2many': return 2.2;
+ case 'many2one': return 1.5;
+ case 'monetary': return 1.2;
+ case 'one2many': return 2.2;
+ case 'reference': return 1.5;
+ case 'selection': return 1.5;
+ case 'text': return 3;
+ default: return 1;
+ }
+ },
+ /**
*
* @returns {integer}
*/
@@ -655,6 +690,30 @@ ListRenderer.include({
});
},
/**
+ * Overridden to set weights on columns for the fixed layout.
+ *
+ * @override
+ * @private
+ */
+ _processColumns: function () {
+ this._super.apply(this, arguments);
+
+ if (this.editable) {
+ var self = this;
+ this.columns.forEach(function (column) {
+ if (column.attrs.width_factor) {
+ column.attrs.widthFactor = parseFloat(column.attrs.width_factor, 10);
+ } else {
+ if (column.tag === 'field') {
+ column.attrs.widthFactor = self._getColumnWidthFactor(column);
+ } else {
+ column.attrs.widthFactor = 1;
+ }
+ }
+ });
+ }
+ },
+ /**
* @override
* @returns {Promise}
*/
@@ -709,6 +768,34 @@ ListRenderer.include({
return $body;
},
/**
+ * Override to optionally add a th in the header for the remove icon column.
+ *
+ * @override
+ * @private
+ */
+ _renderHeader: function () {
+ var $thead = this._super.apply(this, arguments);
+
+ if (this.editable) {
+ var totalWidth = this.columns.reduce(function (acc, column) {
+ return acc + column.attrs.widthFactor;
+ }, 0);
+ this.columns.forEach(function (column) {
+ var $cell = $thead.find('th[data-name=' + column.attrs.name + ']');
+ if (column.attrs.width) {
+ $cell.css('width', column.attrs.width);
+ } else if (column.attrs.widthFactor) {
+ $cell.css('width', (column.attrs.widthFactor / totalWidth * 100) + '%');
+ }
+ });
+ }
+
+ if (this.addTrashIcon) {
+ $thead.find('tr').append($('<th>', {class: 'o_list_record_remove_header'}));
+ }
+ return $thead;
+ },
+ /**
* Editable rows are possibly extended with a trash icon on their right, to
* allow deleting the corresponding record.
* For many2many editable lists, the trash bin is replaced by X.
diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js
index 670f311c195..7a46e3b3cf2 100644
--- a/addons/web/static/src/js/views/list/list_renderer.js
+++ b/addons/web/static/src/js/views/list/list_renderer.js
@@ -54,7 +54,6 @@ var ListRenderer = BasicRenderer.extend({
// This attribute lets us know if there is a handle widget on a field,
// and on which field it is set.
this.handleField = null;
- this._processColumns(params.columnInvisibleFields || {});
this.rowDecorations = _.chain(this.arch.attrs)
.pick(function (value, key) {
return DECORATIONS.indexOf(key) >= 0;
@@ -67,6 +66,7 @@ var ListRenderer = BasicRenderer.extend({
this.editable = params.editable;
this.isGrouped = this.state.groupedBy.length > 0;
this.groupbys = params.groupbys;
+ this._processColumns(params.columnInvisibleFields || {});
},
//--------------------------------------------------------------------------
@@ -188,7 +188,7 @@ var ListRenderer = BasicRenderer.extend({
*/
_processColumns: function (columnInvisibleFields) {
var self = this;
- self.handleField = null;
+ this.handleField = null;
this.columns = _.reject(this.arch.children, function (c) {
if (c.tag === 'control' || c.tag === 'groupby') {
return true;
@@ -313,7 +313,7 @@ var ListRenderer = BasicRenderer.extend({
isPassword: 'password' in node.attrs,
});
this._handleAttributes($td, node);
- return $td.html(formattedValue);
+ return $td.html(formattedValue).attr('title', formattedValue);
},
/**
* Renders the button element associated to the given node and record.
@@ -641,13 +641,14 @@ var ListRenderer = BasicRenderer.extend({
}
var description;
if (node.attrs.widget) {
+ $th.addClass(' o_' + node.attrs.widget + '_cell');
description = this.state.fieldsInfo.list[name].Widget.prototype.description;
}
if (description === undefined) {
description = node.attrs.string || field.string;
}
$th.text(description)
- .data('name', name)
+ .attr('data-name', name)
.toggleClass('o-sort-down', isNodeSorted ? !order[0].asc : false)
.toggleClass('o-sort-up', isNodeSorted ? order[0].asc : false)
.addClass(field.sortable && 'o_column_sortable');
@@ -669,6 +670,8 @@ var ListRenderer = BasicRenderer.extend({
attrs: node.attrs,
};
this._addFieldTooltip(fieldDescr, $th);
+ } else {
+ $th.attr('title', description);
}
return $th;
},
@@ -722,7 +725,7 @@ var ListRenderer = BasicRenderer.extend({
if (disableInput) {
$content.find("input[type='checkbox']").prop('disabled', disableInput);
}
- return $('<' + tag + ' width="1">')
+ return $('<' + tag + '>')
.addClass('o_list_record_selector')
.append($content);
},
diff --git a/addons/web/static/src/scss/list_view.scss b/addons/web/static/src/scss/list_view.scss
index 0882560cb10..fbd12c7e8a4 100644
--- a/addons/web/static/src/scss/list_view.scss
+++ b/addons/web/static/src/scss/list_view.scss
@@ -21,16 +21,18 @@
thead {
color: $o-main-text-color;
border-bottom: 1px solid #cacaca;
- > tr > th {
+ > tr > th:not(.o_list_record_selector) {
border-left: 1px solid #dfdfdf;
- @include media-breakpoint-down(sm) {
- white-space: nowrap;
- }
+ @include o-text-overflow(table-cell);
&:not(.o_column_sortable):hover {
cursor: default;
}
}
}
+ tbody > tr > td:not(.o_list_record_selector) {
+ @include o-text-overflow(table-cell);
+ white-space: normal;
+ }
tfoot {
cursor: default;
@@ -76,7 +78,7 @@
}
}
- .o_list_record_selector, .o_list_record_remove, .o_handle_cell {
+ .o_list_record_selector {
width: 1px; // to prevent the column to expand
}
@@ -161,6 +163,18 @@
//--------------------------------------------------------------------------
// Edition
//--------------------------------------------------------------------------
+
+ &.o_editable_list {
+ table-layout: fixed;
+
+ .o_list_record_selector {
+ width: 40px;
+ }
+ .o_list_record_remove_header, .o_handle_cell {
+ width: 32px;
+ }
+ }
+
.o_data_row.o_selected_row > .o_data_cell:not(.o_readonly_modifier) {
position: relative;