[FIX] web: no quick edit on mouse text selection
Do not trigger quick edit when we are selection text with mouse: - click and holding to select text - multiple clicks selecting text Since click on an editable field now change the edit mode, we could no longer select the text. With this change, quick edit is delayed by a given delay and if the edit mode is not enabled if: - there is a subsequent click within the delay - there is a text selection when the click event is handled closes #68023 X-original-commit: 2939ea4dd4736e659cc3e4df2226a3b08ac8ec48
This commit is contained in:
@@ -20,6 +20,10 @@ var FormController = BasicController.extend({
|
||||
form_dialog_discarded: '_onFormDialogDiscarded',
|
||||
quick_edit: '_onQuickEdit',
|
||||
}),
|
||||
/**
|
||||
* Time between multiple clicks (used to detect double click text selection)
|
||||
*/
|
||||
multiClickTime: 350,
|
||||
/**
|
||||
* @override
|
||||
*
|
||||
@@ -35,6 +39,9 @@ var FormController = BasicController.extend({
|
||||
this.defaultButtons = params.defaultButtons;
|
||||
this.hasActionMenus = params.hasActionMenus;
|
||||
this.toolbarActions = params.toolbarActions || {};
|
||||
// Quick edit is delayed by `multiClickTime` time. If a subsequent click
|
||||
// happens within this time, the quick edit is aborted.
|
||||
this.quickEditTimeout = undefined;
|
||||
},
|
||||
/**
|
||||
* Called each time the form view is attached into the DOM
|
||||
@@ -691,9 +698,14 @@ var FormController = BasicController.extend({
|
||||
*/
|
||||
_onQuickEdit: async function (ev) {
|
||||
ev.stopPropagation();
|
||||
if (this.activeActions.edit) {
|
||||
await this._setEditMode();
|
||||
this.renderer.quickEdit(ev.data);
|
||||
clearTimeout(this.quickEditTimeout);
|
||||
if (this.activeActions.edit && !window.getSelection().toString()) {
|
||||
this.quickEditTimeout = setTimeout(async () => {
|
||||
if (!this.isDestroyed()) {
|
||||
await this._setEditMode();
|
||||
this.renderer.quickEdit(ev.data);
|
||||
}
|
||||
}, this.multiClickTime);
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@ var basicFields = require('web.basic_fields');
|
||||
var concurrency = require('web.concurrency');
|
||||
var config = require('web.config');
|
||||
var core = require('web.core');
|
||||
var FormController = require('web.FormController');
|
||||
var FormView = require('web.FormView');
|
||||
var KanbanView = require('web.KanbanView');
|
||||
var ListView = require('web.ListView');
|
||||
@@ -150,7 +151,14 @@ QUnit.module('basic_fields', {
|
||||
}]
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
testUtils.mock.patch(FormController, {
|
||||
'multiClickTime': 0,
|
||||
});
|
||||
},
|
||||
afterEach() {
|
||||
testUtils.mock.unpatch(FormController);
|
||||
},
|
||||
}, function () {
|
||||
|
||||
QUnit.module('DebouncedField');
|
||||
|
||||
@@ -2,6 +2,7 @@ odoo.define('web.field_many_to_one_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var BasicModel = require('web.BasicModel');
|
||||
var FormController = require('web.FormController');
|
||||
var FormView = require('web.FormView');
|
||||
var ListView = require('web.ListView');
|
||||
var relationalFields = require('web.relational_fields');
|
||||
@@ -151,6 +152,13 @@ QUnit.module('fields', {}, function () {
|
||||
}]
|
||||
},
|
||||
};
|
||||
|
||||
testUtils.mock.patch(FormController, {
|
||||
'multiClickTime': 0,
|
||||
});
|
||||
},
|
||||
afterEach: function () {
|
||||
testUtils.mock.unpatch(FormController);
|
||||
},
|
||||
}, function () {
|
||||
QUnit.module('FieldMany2One');
|
||||
|
||||
@@ -5,6 +5,7 @@ var AbstractField = require('web.AbstractField');
|
||||
var AbstractStorageService = require('web.AbstractStorageService');
|
||||
const ControlPanel = require('web.ControlPanel');
|
||||
const fieldRegistry = require('web.field_registry');
|
||||
var FormController = require('web.FormController');
|
||||
var FormView = require('web.FormView');
|
||||
var KanbanRecord = require('web.KanbanRecord');
|
||||
var ListRenderer = require('web.ListRenderer');
|
||||
@@ -163,7 +164,14 @@ QUnit.module('fields', {}, function () {
|
||||
}]
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
testUtils.mock.patch(FormController, {
|
||||
'multiClickTime': 0,
|
||||
});
|
||||
},
|
||||
afterEach: function () {
|
||||
testUtils.mock.unpatch(FormController);
|
||||
},
|
||||
}, function () {
|
||||
QUnit.module('FieldOne2Many');
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ odoo.define('web.relational_fields_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var AbstractStorageService = require('web.AbstractStorageService');
|
||||
var FormController = require('web.FormController');
|
||||
var FormView = require('web.FormView');
|
||||
var ListView = require('web.ListView');
|
||||
var RamStorage = require('web.RamStorage');
|
||||
@@ -169,6 +170,13 @@ QUnit.module('relational_fields', {
|
||||
onchanges: {},
|
||||
},
|
||||
};
|
||||
|
||||
testUtils.mock.patch(FormController, {
|
||||
'multiClickTime': 0,
|
||||
});
|
||||
},
|
||||
afterEach: function () {
|
||||
testUtils.mock.unpatch(FormController);
|
||||
},
|
||||
}, function () {
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ var concurrency = require('web.concurrency');
|
||||
var core = require('web.core');
|
||||
var fieldRegistry = require('web.field_registry');
|
||||
const fieldRegistryOwl = require('web.field_registry_owl');
|
||||
const FormController = require('web.FormController');
|
||||
const FormRenderer = require('web.FormRenderer');
|
||||
var FormView = require('web.FormView');
|
||||
var mixins = require('web.mixins');
|
||||
@@ -151,6 +152,13 @@ QUnit.module('Views', {
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'kanban'], [false, 'form']],
|
||||
}];
|
||||
|
||||
testUtils.mock.patch(FormController, {
|
||||
'multiClickTime': 0,
|
||||
});
|
||||
},
|
||||
afterEach: function () {
|
||||
testUtils.mock.unpatch(FormController);
|
||||
},
|
||||
}, function () {
|
||||
|
||||
@@ -10674,6 +10682,7 @@ QUnit.module('Views', {
|
||||
assert.containsNone(document.body, '.modal');
|
||||
|
||||
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
|
||||
await testUtils.nextTick(); // wait for quick edit
|
||||
|
||||
assert.containsOnce(form, '.o_form_view.o_form_editable',
|
||||
'should switch into edit mode');
|
||||
@@ -11098,6 +11107,60 @@ QUnit.module('Views', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Quick Edition: selecting text of quick editable field', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
const MULTI_CLICK_TIME = 50;
|
||||
|
||||
testUtils.mock.patch(FormController, {
|
||||
'multiClickTime': MULTI_CLICK_TIME,
|
||||
});
|
||||
|
||||
const form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: `
|
||||
<form>
|
||||
<group>
|
||||
<field name="display_name"/>
|
||||
</group>
|
||||
</form>`,
|
||||
res_id: 1,
|
||||
});
|
||||
|
||||
assert.containsOnce(form, '.o_form_view.o_form_readonly');
|
||||
|
||||
// text selected by holding and dragging doesn't start quick edit
|
||||
window.getSelection().removeAllRanges();
|
||||
const range = document.createRange();
|
||||
await range.selectNode(form.$('.o_field_widget[name="display_name"]')[0]);
|
||||
window.getSelection().addRange(range);
|
||||
await testUtils.dom.click(form.$('.o_field_widget[name="display_name"]'));
|
||||
await concurrency.delay(MULTI_CLICK_TIME);
|
||||
assert.containsOnce(form, '.o_form_view.o_form_readonly');
|
||||
|
||||
// double click selecting text doesn't start quick edit
|
||||
window.getSelection().removeAllRanges();
|
||||
await testUtils.dom.click(form.$('.o_field_widget[name="display_name"]'));
|
||||
range.selectNode(form.$('.o_field_widget[name="display_name"]')[0]);
|
||||
window.getSelection().addRange(range);
|
||||
await testUtils.dom.click(form.$('.o_field_widget[name="display_name"]'));
|
||||
await concurrency.delay(MULTI_CLICK_TIME);
|
||||
assert.containsOnce(form, '.o_form_view.o_form_readonly');
|
||||
|
||||
// quick edit happens after timeout
|
||||
window.getSelection().removeAllRanges();
|
||||
await testUtils.dom.click(form.$('.o_field_widget[name="display_name"]'));
|
||||
await testUtils.nextTick();
|
||||
assert.containsOnce(form, '.o_form_view.o_form_readonly');
|
||||
await concurrency.delay(MULTI_CLICK_TIME);
|
||||
assert.containsOnce(form, '.o_form_view.o_form_editable');
|
||||
|
||||
// FormController unpatch done in afterEach
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("attach callbacks with long processing in __renderView", async function (assert) {
|
||||
/**
|
||||
* The main use case of this test is discuss, in which the FormRenderer
|
||||
|
||||
Reference in New Issue
Block a user