[IMP] web: add quick edit behaviour

This commit adds the quick edit behaviour.
The quick edit allows to click on fields in readonly form view to switch
into edit mode. After switching mode, the clicked field is automatically
focused.
A few fields have a custom quick edit behaviour after mode switched:
  - checkboxes automatically toggle.
  - radio buttons are set to the selected value.
  - one2many list's cell are focused.
One2many list fields now show the "add a line" in readonly mode.

task 2330101
This commit is contained in:
Michael Mattiello (mcm)
2021-02-02 12:40:23 +00:00
parent d1c56ec7c4
commit 2c3ac6b254
21 changed files with 1275 additions and 147 deletions
@@ -212,7 +212,7 @@ QUnit.module('basic_fields', {
QUnit.module('FieldBoolean');
QUnit.test('boolean field in form view', async function (assert) {
assert.expect(13);
assert.expect(15);
var form = await createView({
View: FormView,
@@ -224,11 +224,15 @@ QUnit.module('basic_fields', {
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should be checked");
assert.containsNone(form, '.o_field_boolean input:disabled',
'checkbox should not be disabled');
// switch to edit mode and check the result
await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should still be checked");
assert.containsNone(form, '.o_field_boolean input:disabled',
'checkbox should not be disabled');
// uncheck the checkbox
await testUtils.dom.click(form.$('.o_field_boolean input:checked'));
@@ -350,6 +354,41 @@ QUnit.module('basic_fields', {
list.destroy();
});
QUnit.test('readonly boolean field', async function (assert) {
assert.expect(6);
const form = await createView({
View: FormView,
model: 'partner',
data: this.data,
arch: `
<form>
<field name="bar" attrs="{'readonly': True}"/>
</form>`,
res_id: 1,
});
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should be checked");
assert.containsOnce(form, '.o_field_boolean input:disabled',
'checkbox should be disabled');
await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should still be checked");
assert.containsOnce(form, '.o_field_boolean input:disabled',
'checkbox should still be disabled');
await testUtils.dom.click(form.$('.o_field_boolean label'));
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should still be checked");
assert.containsOnce(form, '.o_field_boolean input:disabled',
'checkbox should still be disabled');
form.destroy();
});
QUnit.module('FieldBooleanToggle');
QUnit.test('use boolean toggle widget in form view', async function (assert) {
@@ -2879,10 +2918,19 @@ QUnit.module('basic_fields', {
data: this.data,
arch: '<form string="Partners">' +
'<field name="document" widget="image" options="{\'size\': [90, 90]}"/>' +
'<field name="timmy" widget="many2many">' +
'<tree>' +
'<field name="timmy" widget="many2many" mode="kanban">' +
// use kanban view as the tree will trigger edit mode
// and thus won't display the field
'<kanban>' +
'<field name="display_name"/>' +
'</tree>' +
'<templates>' +
'<t t-name="kanban-box">' +
'<div class="oe_kanban_global_click">' +
'<span><t t-esc="record.display_name.value"/></span>' +
'</div>' +
'</t>' +
'</templates>' +
'</kanban>' +
'<form>' +
'<field name="image" widget="image"/>' +
'</form>' +
@@ -2903,11 +2951,11 @@ QUnit.module('basic_fields', {
});
assert.verifySteps(["The view's image should have been fetched"]);
assert.containsOnce(form, 'tr.o_data_row',
assert.containsOnce(form, '.o_kanban_record.oe_kanban_global_click',
'There should be one record in the many2many');
// Actual flow: click on an element of the m2m to get its form view
await testUtils.dom.click(form.$('tbody td:contains(gold)'));
await testUtils.dom.click(form.$('.oe_kanban_global_click'));
assert.strictEqual($('.modal').length, 1,
'The modal should have opened');
assert.verifySteps(["The dialog's image should have been fetched"]);
@@ -3032,10 +3080,19 @@ QUnit.module('basic_fields', {
data: this.data,
arch: '<form string="Partners">' +
'<field name="foo" widget="image_url" options="{\'size\': [90, 90]}"/>' +
'<field name="timmy" widget="many2many">' +
'<tree>' +
'<field name="timmy" widget="many2many" mode="kanban">' +
// use kanban view as the tree will trigger edit mode
// and thus won't display the field
'<kanban>' +
'<field name="display_name"/>' +
'</tree>' +
'<templates>' +
'<t t-name="kanban-box">' +
'<div class="oe_kanban_global_click">' +
'<span><t t-esc="record.display_name.value"/></span>' +
'</div>' +
'</t>' +
'</templates>' +
'</kanban>' +
'<form>' +
'<field name="image" widget="image_url"/>' +
'</form>' +
@@ -3056,11 +3113,11 @@ QUnit.module('basic_fields', {
});
assert.verifySteps(["The view's image should have been fetched"]);
assert.containsOnce(form, 'tr.o_data_row',
assert.containsOnce(form, '.o_kanban_record.oe_kanban_global_click',
'There should be one record in the many2many');
// Actual flow: click on an element of the m2m to get its form view
await testUtils.dom.click(form.$('tbody td:contains(gold)'));
await testUtils.dom.click(form.$('.oe_kanban_global_click'));
assert.strictEqual($('.modal').length, 1,
'The modal should have opened');
assert.verifySteps(["The dialog's image should have been fetched"]);
@@ -4524,7 +4581,8 @@ QUnit.module('basic_fields', {
'<field name="datetime"/>' +
'</tree>' +
'<form>' +
'<field name="datetime" widget="date"/>' +
// display datetime in readonly as modal will open in edit
'<field name="datetime" widget="date" attrs="{\'readonly\': 1}"/>' +
'</form>' +
'</field>' +
'</form>',
@@ -4568,7 +4626,8 @@ QUnit.module('basic_fields', {
'<field name="datetime"/>' +
'</tree>' +
'<form>' +
'<field name="datetime" widget="date"/>' +
// display datetime in readonly as modal will open in edit
'<field name="datetime" widget="date" attrs="{\'readonly\': 1}"/>' +
'</form>' +
'</field>' +
'</form>',