summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/account/static/src/js/section_and_note_fields_backend.js4
-rw-r--r--addons/web/static/src/js/core/dom.js2
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js14
-rw-r--r--addons/web/static/src/js/fields/field_registry.js1
-rw-r--r--addons/web/static/src/js/views/list/list_editable_renderer.js9
-rw-r--r--addons/web/static/src/scss/list_view.scss140
-rw-r--r--addons/web/static/tests/views/list_tests.js55
7 files changed, 131 insertions, 94 deletions
diff --git a/addons/account/static/src/js/section_and_note_fields_backend.js b/addons/account/static/src/js/section_and_note_fields_backend.js
index 1f232ac0db8..8d9ab57cee4 100644
--- a/addons/account/static/src/js/section_and_note_fields_backend.js
+++ b/addons/account/static/src/js/section_and_note_fields_backend.js
@@ -9,7 +9,7 @@ odoo.define('account.section_and_note_backend', function (require) {
var FieldChar = require('web.basic_fields').FieldChar;
var FieldOne2Many = require('web.relational_fields').FieldOne2Many;
var fieldRegistry = require('web.field_registry');
-var FieldText = require('web.basic_fields').FieldText;
+var ListFieldText = require('web.basic_fields').ListFieldText;
var ListRenderer = require('web.ListRenderer');
var SectionAndNoteListRenderer = ListRenderer.extend({
@@ -94,7 +94,7 @@ var SectionAndNoteFieldOne2Many = FieldOne2Many.extend({
// and a FieldText for the rest (product and note).
var SectionAndNoteFieldText = function (parent, name, record, options) {
var isSection = record.data.display_type === 'line_section';
- var Constructor = isSection ? FieldChar : FieldText;
+ var Constructor = isSection ? FieldChar : ListFieldText;
return new Constructor(parent, name, record, options);
};
diff --git a/addons/web/static/src/js/core/dom.js b/addons/web/static/src/js/core/dom.js
index e618b644eaa..81211788246 100644
--- a/addons/web/static/src/js/core/dom.js
+++ b/addons/web/static/src/js/core/dom.js
@@ -102,7 +102,7 @@ var dom = {
}
options = options || {};
- minHeight = (options && options.min_height) || 50;
+ minHeight = 'min_height' in options ? options.min_height : 50;
$fixedTextarea = $('<textarea disabled>', {
class: $textarea[0].className,
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index 1c5c19ebcf8..5919f100bcc 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -1112,6 +1112,7 @@ var FieldText = InputField.extend(TranslatableFieldMixin, {
if (this.mode === 'edit') {
this.tagName = 'textarea';
}
+ this.autoResizeOptions = {parent: this};
},
/**
* As it it done in the start function, the autoresize is done only once.
@@ -1120,7 +1121,7 @@ var FieldText = InputField.extend(TranslatableFieldMixin, {
*/
start: function () {
if (this.mode === 'edit') {
- dom.autoresize(this.$el, {parent: this});
+ dom.autoresize(this.$el, this.autoResizeOptions);
this.$el = this.$el.add(this._renderTranslateButton());
}
@@ -1157,6 +1158,16 @@ var FieldText = InputField.extend(TranslatableFieldMixin, {
},
});
+var ListFieldText = FieldText.extend({
+ /**
+ * @override
+ */
+ init: function () {
+ this._super.apply(this, arguments);
+ this.autoResizeOptions.min_height = 0;
+ },
+});
+
/**
* Displays a handle to modify the sequence.
*/
@@ -2995,6 +3006,7 @@ return {
FieldPhone: FieldPhone,
FieldProgressBar: FieldProgressBar,
FieldText: FieldText,
+ ListFieldText: ListFieldText,
FieldToggleBoolean: FieldToggleBoolean,
HandleWidget: HandleWidget,
InputField: InputField,
diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js
index cd4c92087eb..ccd5dabdff1 100644
--- a/addons/web/static/src/js/fields/field_registry.js
+++ b/addons/web/static/src/js/fields/field_registry.js
@@ -26,6 +26,7 @@ registry
.add('datetime', basic_fields.FieldDateTime)
.add('domain', basic_fields.FieldDomain)
.add('text', basic_fields.FieldText)
+ .add('list.text', basic_fields.ListFieldText)
.add('html', basic_fields.FieldText)
.add('float', basic_fields.FieldFloat)
.add('char', basic_fields.FieldChar)
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 687f046b7e6..040a186d4ee 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
@@ -119,6 +119,10 @@ ListRenderer.include({
* - There is no line in edition (all lines are saved so they are all valid)
* - The line in edition can be saved
*
+ * If the given recordID is a record in the list, toggle a className on its
+ * row's cells for invalid fields, so that we can style those cells
+ * differently.
+ *
* @override
* @param {string} [recordID]
* @returns {string[]}
@@ -130,7 +134,10 @@ ListRenderer.include({
return [];
}
}
- return this._super(recordID);
+ var fieldNames = this._super(recordID);
+ this.$('.o_selected_row .o_data_cell').removeClass('o_invalid_cell');
+ this.$('.o_selected_row .o_data_cell:has(> .o_field_invalid)').addClass('o_invalid_cell');
+ return fieldNames;
},
/**
* We need to override the confirmChange method from BasicRenderer to
diff --git a/addons/web/static/src/scss/list_view.scss b/addons/web/static/src/scss/list_view.scss
index fbd12c7e8a4..16f14f3717e 100644
--- a/addons/web/static/src/scss/list_view.scss
+++ b/addons/web/static/src/scss/list_view.scss
@@ -10,14 +10,6 @@
border-collapse: initial;
border-spacing: 0;
- // Checkbox in editable list
- // should be clickable and activate the row
- &.o_editable_list .o_data_row:not(.o_selected_row) .o_data_cell {
- .custom-checkbox:not(.o_readonly_modifier) {
- pointer-events: none;
- }
- }
-
thead {
color: $o-main-text-color;
border-bottom: 1px solid #cacaca;
@@ -31,7 +23,13 @@
}
tbody > tr > td:not(.o_list_record_selector) {
@include o-text-overflow(table-cell);
- white-space: normal;
+
+ &.o_list_number {
+ text-align: right;
+ }
+ &.o_list_text {
+ white-space: pre-wrap;
+ }
}
tfoot {
@@ -144,15 +142,6 @@
}
}
- // Values styling
- .o_list_number {
- text-align: right;
- white-space: nowrap;
- }
- .o_list_text {
- white-space: pre-wrap;
- }
-
.o_data_cell.o_text_overflow,
.o_data_cell.o_invisible_modifier {
// Override display: none to keep table cells aligned. Note: cannot use
@@ -173,89 +162,62 @@
.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;
-
- // The in-edition elements will overflow other elements (the rows below,
- // the content below the list view, ...). As those might be using
- // position: relative, the in-edition elements have to define a z-index.
- // Technically, creating a stacking context for a meaningful parent
- // (maybe the .o_content) might be required for safety but we should
- // consider this later if needed.
- z-index: 1;
-
- // The in-edition elements will overflow other elements (the rows below,
- // the content below the list view, ...). As those might be using
- // position: relative, the in-edition elements have to define a z-index.
- // Technically, creating a stacking context for a meaningful parent
- // (maybe the .o_content) might be required for safety but we should
- // consider this later if needed.
- z-index: 1;
-
- // Field widgets override
- > .o_field_widget {
- @include o-position-absolute(0, 0, auto, 0);
- min-height: 100%;
-
- &:not(.o_field_text) {
- white-space: nowrap;
+ // checkboxes in editable lists should be clickable and activate the row
+ .o_data_row:not(.o_selected_row) .o_data_cell {
+ .custom-checkbox:not(.o_readonly_modifier) {
+ pointer-events: none;
}
-
- &.o_field_many2manytags > .badge {
- &, > .o_badge_text {
- white-space: normal;
- max-width: 100%; // Fix a chrome bug where badge would not break on multiple lines
- }
- }
- }
- > .o_field_translate {
- @include o-position-absolute(0, 5px);
- width: 16px; // to have some space on the right
}
- .o_input {
- padding: $table-cell-padding-sm;
+
+ .o_data_row.o_selected_row > .o_data_cell:not(.o_readonly_modifier) {
+ position: relative; // for o_field_translate
background-color: white;
.o_input {
- padding: 0!important;
+ border: none;
+ padding: 0;
}
- }
- .o_input_dropdown {
- min-height: 100%;
- }
- .o_field_monetary input {
- width: 0;
- }
- .o_field_boolean {
- position: relative!important;
- }
- .o_field_widget {
- min-width: 0;
- }
- .o_input_dropdown, .o_datepicker {
- > .o_input {
- padding-right: 15px; // To prevent caret overlapping
+ > .o_field_text {
+ vertical-align: top;
}
- > .o_dropdown_button, .o_datepicker_button {
- @include o-position-absolute(20%, 5px);
+ > .o_field_widget {
+ width: 100%;
+ > .o_external_button {
+ padding: 0;
+ border: none;
+ background-color: inherit;
+ margin-left: 5px;
+ font-size: 12px;
+ }
+ }
+ > .o_field_monetary input {
+ width: 0; // override width: 100px and let flex makes this input grow
+ margin: 0 4px;
+ }
+ > .o_field_many2manytags > .o_field_many2one {
+ // reduce basis to prevent many2one input from going to the next line to often
+ flex-basis: 40px;
+ }
+ .o_input_dropdown, .o_datepicker {
+ > .o_input {
+ padding-right: 15px; // to prevent caret overlapping
+ }
+ > .o_dropdown_button, .o_datepicker_button {
+ @include o-position-absolute(0, 0);
+ }
+ }
+ > .o_field_translate {
+ @include o-position-absolute(0, 5px);
+ width: 16px; // to have some space on the right
+ }
+ > .o_row_handle {
+ visibility: hidden; // hide sequence when editing
}
- }
- .o_field_widget > .o_external_button {
- padding: 0;
- background-color: inherit;
- margin-left: 3px;
- }
- .o_row_handle {
- visibility: hidden; // Hide sequence when editing
- }
- .o_field_boolean {
- width: auto!important; // Override the width computed in JS (needed for Chrome)
}
}
- .o_field_x2many_list_row_add {
+ .o_field_x2many_list_row_add, .o_group_field_row_add {
a:focus, a:active {
color: $link-hover-color;
outline: none;
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index 2584c047508..d4efb3154a4 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -13,6 +13,7 @@ var testUtils = require('web.test_utils');
var widgetRegistry = require('web.widget_registry');
var Widget = require('web.Widget');
+var _t = core._t;
var createView = testUtils.createView;
@@ -25,6 +26,7 @@ QUnit.module('Views', {
bar: {string: "Bar", type: "boolean"},
date: {string: "Some Date", type: "date"},
int_field: {string: "int_field", type: "integer", sortable: true, group_operator: "sum"},
+ text: {string: "text field", type: "text"},
qux: {string: "my float", type: "float"},
m2o: {string: "M2O field", type: "many2one", relation: "bar"},
o2m: {string: "O2M field", type: "one2many", relation: "bar"},
@@ -1222,6 +1224,59 @@ QUnit.module('Views', {
list.destroy();
});
+ QUnit.test('row height should not change when switching mode', async function (assert) {
+ // Warning: this test is css dependant
+ assert.expect(3);
+
+ var multiLang = _t.database.multi_lang;
+ _t.database.multi_lang = true;
+
+ this.data.foo.fields.foo.translate = true;
+ this.data.foo.fields.boolean = {type: 'boolean', string: 'Bool'};
+ var currencies = {};
+ _.each(this.data.res_currency.records, function (currency) {
+ currencies[currency.id] = currency;
+ });
+
+ var list = await createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '<tree editable="top">' +
+ '<field name="foo" required="1"/>' +
+ '<field name="int_field" readonly="1"/>' +
+ '<field name="boolean"/>' +
+ '<field name="date"/>' +
+ '<field name="text" width_factor="2"/>' +
+ '<field name="amount"/>' +
+ '<field name="currency_id" invisible="1"/>' +
+ '<field name="m2o"/>' +
+ '<field name="m2m" widget="many2many_tags"/>' +
+ '</tree>',
+ session: {
+ currencies: currencies,
+ },
+ });
+ var startHeight = list.$('.o_data_row:first').height();
+
+ // start edition of first row
+ await testUtils.dom.click(list.$('.o_data_row:first > td:not(.o_list_record_selector)').first());
+
+ assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row');
+ var editionHeight = list.$('.o_data_row:first').height();
+
+ // leave edition
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+
+ var readonlyHeight = list.$('.o_data_row:first').height();
+
+ assert.strictEqual(startHeight, editionHeight);
+ assert.strictEqual(startHeight, readonlyHeight);
+
+ _t.database.multi_lang = multiLang;
+ list.destroy();
+ });
+
QUnit.test('deleting one record', async function (assert) {
assert.expect(5);