summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js30
-rw-r--r--addons/web/static/src/js/views/list/list_editable_renderer.js83
-rw-r--r--addons/web/static/src/js/views/list/list_renderer.js1
-rw-r--r--addons/web/static/src/scss/list_view.scss6
4 files changed, 101 insertions, 19 deletions
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index fcae2043d00..eefb771c69a 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -17,10 +17,11 @@ var AbstractField = require('web.AbstractField');
var basicFields = require('web.basic_fields');
var concurrency = require('web.concurrency');
var ControlPanelView = require('web.ControlPanelView');
-var dialogs = require('web.view_dialogs');
var core = require('web.core');
var data = require('web.data');
var Dialog = require('web.Dialog');
+var dialogs = require('web.view_dialogs');
+var dom = require('web.dom');
var KanbanRecord = require('web.KanbanRecord');
var KanbanRenderer = require('web.KanbanRenderer');
var ListRenderer = require('web.ListRenderer');
@@ -905,6 +906,22 @@ var FieldX2Many = AbstractField.extend({
start: function () {
return this._renderControlPanel().then(this._super.bind(this));
},
+ /**
+ * For the list renderer to properly work, it must know if it is in the DOM,
+ * and be notified when it is attached to the DOM.
+ */
+ on_attach_callback: function () {
+ this.isInDOM = true;
+ if (this.renderer) {
+ this.renderer.on_attach_callback();
+ }
+ },
+ /**
+ * For the list renderer to properly work, it must know if it is in the DOM.
+ */
+ on_detach_callback: function () {
+ this.isInDOM = false;
+ },
//--------------------------------------------------------------------------
// Public
@@ -1096,7 +1113,16 @@ var FieldX2Many = AbstractField.extend({
this.renderer = new Renderer(this, this.value, rendererParams);
this.$el.addClass('o_field_x2many o_field_x2many_' + viewType);
- return this.renderer ? this.renderer.appendTo(this.$el) : this._super();
+ if (this.renderer) {
+ return this.renderer.appendTo(document.createDocumentFragment()).then(function () {
+ dom.append(self.$el, self.renderer.$el, {
+ in_DOM: self.isInDOM,
+ callbacks: [{widget: self.renderer}],
+ });
+ });
+ } else {
+ return this._super();
+ }
},
/**
* Instanciates a control panel with the appropriate buttons and a pager.
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 65f5b433c27..9275d414578 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
@@ -43,6 +43,8 @@ ListRenderer.include({
var self = this;
this._super.apply(this, arguments);
+ this.editable = params.editable;
+
// if addCreateLine (resp. addCreateLineInGroups) is true, the renderer
// will add a 'Add a line' link at the bottom of the list view (resp.
// at the bottom of each group)
@@ -107,6 +109,29 @@ ListRenderer.include({
}
return this._super();
},
+ /**
+ * The list renderer needs to know if it is in the DOM, and to be notified
+ * when it is attached to the DOM to properly compute column widths.
+ *
+ * @override
+ */
+ on_attach_callback: function () {
+ this.isInDOM = true;
+ if (this.editable) {
+ this._freezeColumnWidths();
+ }
+ this._super();
+ },
+ /**
+ * The list renderer needs to know if it is in the DOM to properly compute
+ * column widths.
+ *
+ * @override
+ */
+ on_detach_callback: function () {
+ this.isInDOM = false;
+ this._super();
+ },
//--------------------------------------------------------------------------
// Public
@@ -493,9 +518,39 @@ ListRenderer.include({
}
},
/**
+ * This function freezes the column widths and forces a fixed table-layout,
+ * once the browser has computed the optimal width of each column according
+ * to the displayed records. We want to freeze widths s.t. it doesn't
+ * flicker when we switch a row in edition.
+ *
+ * We skip this when there is no record as we don't want to fix widths
+ * according to column's labels. In this case, we fallback on the 'weight'
+ * heuristic, which assigns to each column a fixed or relative width
+ * depending on the widget or field type.
+ *
+ * Note that the list must be in the DOM when this function is called.
+ *
+ * @private
+ */
+ _freezeColumnWidths: function () {
+ if (!this.state.data.length) {
+ // there is no record -> don't force column's widths w.r.t. their label
+ return;
+ }
+ var $thead = this.$('thead');
+ $thead.find('th').each(function () {
+ var $th = $(this);
+ $th.css('width', $th.outerWidth() + 'px');
+ });
+ this.$('table').css('table-layout', 'fixed');
+ },
+ /**
* Returns the relative width according to the widget or the field type.
- * @see _renderHeader
+ * This is only used when there is no record in the list (i.e. when we can't
+ * let the browser compute the optimal width of each column).
*
+ * @see _renderHeader
+ * @private
* @param {Object} column an arch node
* @returns {integer | string} either a weight factor (number) or a css
* width description (string)
@@ -516,22 +571,13 @@ ListRenderer.include({
return widget.widthFactor;
}
switch (field.type) {
- case 'binary': return 1;
case 'boolean': return '40px';
- case 'char': return 2;
case 'date': return '92px';
case 'datetime': return '146px';
case 'float': return '92px';
- case 'html': return 3;
case 'integer': return '74px';
- case 'many2many': return 2;
- case 'many2one': return 2;
case 'monetary': return '104px';
- case 'one2many': return 2;
- case 'reference': return 1.5;
- case 'selection': return 1.5;
- case 'text': return 2.5;
- default: return 1;
+ default: return 1; // evenly distribute the remaining space
}
},
/**
@@ -842,7 +888,7 @@ ListRenderer.include({
_renderHeader: function () {
var $thead = this._super.apply(this, arguments);
- if (this.editable) {
+ if (this.editable && !this.state.data.length) {
// we compute the sum of the weights for each columns, excluding
// those with a fixed width.
var totalWidth = this.columns.reduce(function (acc, column) {
@@ -934,8 +980,17 @@ ListRenderer.include({
this.currentRow = null;
this.allRecordsIds = null;
return this._super.apply(this, arguments).then(function () {
- if (self.editable) {
- self.$('table').addClass('o_editable_list');
+ var table = self.el.getElementsByTagName('table')[0];
+ if (table) { // no table if no content helper displayed
+ if (!self.state.data.length) { // FIXME: only handles ungrouped case
+ table.classList.add('o_empty_list');
+ }
+ if (self.editable) {
+ table.classList.add('o_editable_list');
+ if (self.isInDOM) {
+ self._freezeColumnWidths();
+ }
+ }
}
});
},
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 fda8d12f9e4..98c8bf71046 100644
--- a/addons/web/static/src/js/views/list/list_renderer.js
+++ b/addons/web/static/src/js/views/list/list_renderer.js
@@ -67,7 +67,6 @@ var ListRenderer = BasicRenderer.extend({
this.hasSelectors = params.hasSelectors;
this.selection = params.selectedRecords || [];
this.pagers = []; // instantiated pagers (only for grouped lists)
- this.editable = params.editable;
this.isGrouped = this.state.groupedBy.length > 0;
this.groupbys = params.groupbys;
},
diff --git a/addons/web/static/src/scss/list_view.scss b/addons/web/static/src/scss/list_view.scss
index f2fc83902a4..148ec6af348 100644
--- a/addons/web/static/src/scss/list_view.scss
+++ b/addons/web/static/src/scss/list_view.scss
@@ -55,7 +55,7 @@
}
}
- .o_column_sortable {
+ .o_column_sortable:not(.o_handle_cell) {
position: relative;
user-select: none; // Prevent unwanted selection while sorting
@@ -180,7 +180,9 @@
//--------------------------------------------------------------------------
&.o_editable_list {
- table-layout: fixed;
+ &.o_empty_list {
+ table-layout: fixed;
+ }
.o_list_record_remove_header, .o_handle_cell {
width: 32px;