From 1824020cc274f3ef6e86fec5248d49ffde86e480 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Fri, 16 Aug 2019 11:02:49 +0000 Subject: [PATCH] [IMP] web: list: keep columns width when adding records Mainly, when adding the first record to the list, as this is when we switch from forcing the column's widths (when there is no data), to letting the browser optimally divide the available space. Some other cases had to be handled, like the multi edition. --- .../static/src/js/fields/relational_fields.js | 1 + .../src/js/views/list/list_controller.js | 4 +- .../js/views/list/list_editable_renderer.js | 25 +++++- .../relational_fields/field_one2many_tests.js | 65 ++++++++++++++ addons/web/static/tests/views/list_tests.js | 88 +++++++++++++++++++ 5 files changed, 178 insertions(+), 5 deletions(-) diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index eefb771c69a..c539a3ce12d 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -1071,6 +1071,7 @@ var FieldX2Many = AbstractField.extend({ this.currentColInvisibleFields = this._evalColumnInvisibleFields(); return this.renderer.updateState(this.value, { columnInvisibleFields: this.currentColInvisibleFields, + keepWidths: true, }).then(function () { self.pager.updateState({ size: self.value.count }); }); diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js index c09abc54b91..1e109d7c0b8 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -247,7 +247,7 @@ var ListController = BasicController.extend({ }); }).then(function (recordID) { var state = self.model.get(self.handle); - self.renderer.updateState(state, {}) + self.renderer.updateState(state, {keepWidths: true}) .then(function () { self.renderer.editRecord(recordID); }).then(self._updatePager.bind(self)); @@ -405,7 +405,7 @@ var ListController = BasicController.extend({ .then(() => { this._updateButtons('readonly'); const state = this.model.get(this.handle); - this.renderer.updateState(state, {}); + this.renderer.updateState(state, {keepWidths: true}); resolve(Object.keys(changes)); }) .guardedCatch(rejectAndDiscard); 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 a1b23317bf1..b3ee0e43fa4 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 @@ -44,6 +44,7 @@ ListRenderer.include({ this._super.apply(this, arguments); this.editable = params.editable; + this.columnWidths = false; // if addCreateLine (resp. addCreateLineInGroups) is true, the renderer // will add a 'Add a line' link at the bottom of the list view (resp. @@ -491,6 +492,13 @@ ListRenderer.include({ * @override */ updateState: function (state, params) { + this.oldColumns = this.columns; + this.columnWidths = false; + if (params.keepWidths) { + this.columnWidths = this.$('thead th').toArray().map(function (th) { + return $(th).outerWidth(); + }); + } if (params.noRender) { // the state changed, but we won't do a re-rendering right now, so // remove computed modifiers data (as they are obsolete) to force @@ -537,10 +545,21 @@ ListRenderer.include({ // there is no record -> don't force column's widths w.r.t. their label return; } + let restoreWidths = false; + if (this.columnWidths) { + if (this.oldColumns && this.oldColumns.length === this.columns.length) { + for (let i = 0; i < this.oldColumns.length; i++) { + if (this.oldColumns[i] !== this.columns[i]) { + break; + } + restoreWidths = (i === this.oldColumns.length - 1); // columns are as before + } + } + } var $thead = this.$('thead'); - $thead.find('th').each(function () { - var $th = $(this); - $th.css('width', $th.outerWidth() + 'px'); + $thead.find('th').each((index, th) => { + var $th = $(th); + $th.css('width', restoreWidths ? this.columnWidths[index] : $th.outerWidth() + 'px'); }); this.$('table').css('table-layout', 'fixed'); }, diff --git a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js index f4752bc9751..e8d8785b77a 100644 --- a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js +++ b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js @@ -8541,6 +8541,71 @@ QUnit.module('fields', {}, function () { form.destroy(); }); + QUnit.test('column widths are kept when adding first record in o2m', async function (assert) { + assert.expect(2); + + var form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '
', + }); + + var width = form.$('th[data-name="date"]')[0].offsetWidth; + + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + + assert.containsOnce(form, '.o_data_row'); + assert.strictEqual(form.$('th[data-name="date"]')[0].offsetWidth, width); + + form.destroy(); + }); + + QUnit.test('column widths are kept when editing a record in o2m', async function (assert) { + assert.expect(2); + + this.data.partner.records[0].p = [2]; + + var form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '
', + res_id: 1, + viewOptions: { + mode: 'edit', + }, + }); + + var width = form.$('th[data-name="date"]')[0].offsetWidth; + + await testUtils.dom.click(form.$('.o_data_row .o_data_cell:first')); + + assert.strictEqual(form.$('th[data-name="date"]')[0].offsetWidth, width); + + var longVal = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed blandit, ' + + 'justo nec tincidunt feugiat, mi justo suscipit libero, sit amet tempus ipsum ' + + 'purus bibendum est.'; + await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), longVal); + + assert.strictEqual(form.$('th[data-name="date"]')[0].offsetWidth, width); + + form.destroy(); + }); }); }); }); diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 7915ab2964c..c761993b674 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -1517,6 +1517,94 @@ QUnit.module('Views', { list.destroy(); }); + QUnit.test('column widths are kept when adding first record', async function (assert) { + assert.expect(2); + + this.data.foo.records = []; // in this scenario, we start with no records + var list = await createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '' + + '' + + '' + + '', + }); + + var width = list.$('th[data-name="datetime"]')[0].offsetWidth; + + await testUtils.dom.click(list.$buttons.find('.o_list_button_add')); + + assert.containsOnce(list, '.o_data_row'); + assert.strictEqual(list.$('th[data-name="datetime"]')[0].offsetWidth, width); + + list.destroy(); + }); + + QUnit.test('column widths are kept when editing a record', async function (assert) { + assert.expect(3); + + var list = await createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '' + + '' + + '' + + '', + }); + + var width = list.$('th[data-name="datetime"]')[0].offsetWidth; + + await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_data_cell:eq(1)')); + assert.containsOnce(list, '.o_selected_row'); + + var longVal = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed blandit, ' + + 'justo nec tincidunt feugiat, mi justo suscipit libero, sit amet tempus ipsum purus ' + + 'bibendum est.'; + await testUtils.fields.editInput(list.$('.o_field_widget[name=text]'), longVal); + await testUtils.dom.click(list.$buttons.find('.o_list_button_save')); + + assert.containsNone(list, '.o_selected_row'); + assert.strictEqual(list.$('th[data-name="datetime"]')[0].offsetWidth, width); + + list.destroy(); + }); + + QUnit.test('column widths are kept when editing multiple records', async function (assert) { + assert.expect(4); + + var list = await createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '' + + '' + + '' + + '', + }); + + var width = list.$('th[data-name="datetime"]')[0].offsetWidth; + + // select two records and edit + await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_list_record_selector input')); + await testUtils.dom.click(list.$('.o_data_row:eq(1) .o_list_record_selector input')); + await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_data_cell:eq(1)')); + + assert.containsOnce(list, '.o_selected_row'); + var longVal = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed blandit, ' + + 'justo nec tincidunt feugiat, mi justo suscipit libero, sit amet tempus ipsum purus ' + + 'bibendum est.'; + await testUtils.fields.editInput(list.$('.o_field_widget[name=text]'), longVal); + assert.containsOnce(document.body, '.modal'); + await testUtils.dom.click($('.modal .btn-primary')); + + assert.containsNone(list, '.o_selected_row'); + assert.strictEqual(list.$('th[data-name="datetime"]')[0].offsetWidth, width); + + list.destroy(); + }); + QUnit.test('row height should not change when switching mode', async function (assert) { // Warning: this test is css dependant assert.expect(3);