diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index b42cfa0741f..02cb6356658 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -54,17 +54,7 @@ var M2ODialog = Dialog.extend({ this.trigger_up('quick_create', { value: this.value }); }, }, { - text: _t('Create and edit'), - classes: 'btn-primary', - close: true, - click: function () { - this.trigger_up('search_create_popup', { - view_type: 'form', - value: this.value, - }); - }, - }, { - text: _t('Cancel'), + text: _t('Discard'), close: true, }], }); @@ -96,7 +86,6 @@ var FieldMany2One = AbstractField.extend({ 'closed_unset': '_onDialogClosedUnset', 'field_changed': '_onFieldChanged', 'quick_create': '_onQuickCreate', - 'search_create_popup': '_onSearchCreatePopup', }), events: _.extend({}, AbstractField.prototype.events, { 'click input': '_onInputClick', @@ -146,6 +135,9 @@ var FieldMany2One = AbstractField.extend({ // Add default search method for M20 (name_search) this._addAutocompleteSource(this._search, {placeholder: _t('Loading...'), order: 1}); + // list of last autocomplete suggestions + this.suggestions = []; + // use a DropPrevious to properly handle related record quick creations, // and store a createDef to be able to notify the environment that there // is pending quick create operation @@ -260,6 +252,7 @@ var FieldMany2One = AbstractField.extend({ } this.$input.autocomplete({ source: function (req, resp) { + self.suggestions = []; _.each(self._autocompleteSources, function (source) { // Resets the results for this source source.results = []; @@ -274,7 +267,8 @@ var FieldMany2One = AbstractField.extend({ Promise.resolve(source.method.call(self, search)).then(function (results) { source.results = results; source.loading = false; - resp(self._concatenateAutocompleteResults()); + self.suggestions = self._concatenateAutocompleteResults(); + resp(self.suggestions); }); } }); @@ -771,7 +765,13 @@ var FieldMany2One = AbstractField.extend({ * @private */ _onInputFocusout: function () { - if (this.can_create && this.floating) { + if (!this.floating) { + return; + } + const firstValue = this.suggestions.find(s => s.id); + if (firstValue) { + this.reinitialize(firstValue.id); + } else if (this.can_create) { new M2ODialog(this, this.string, this.$input.val()).open(); } }, @@ -827,14 +827,6 @@ var FieldMany2One = AbstractField.extend({ _onQuickCreate: function (event) { this._quickCreate(event.data.value); }, - /** - * @private - * @param {OdooEvent} event - */ - _onSearchCreatePopup: function (event) { - var data = event.data; - this._searchCreatePopup(data.view_type, false, this._createContext(data.value)); - }, }); var Many2oneBarcode = FieldMany2One.extend({ diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 7b4ae80f146..92f360a0abf 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1652,7 +1652,7 @@ - Do you want to create as a new ? + Create as a new ? diff --git a/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js b/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js index 80f5dd89304..1c9dd615c9d 100644 --- a/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js +++ b/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js @@ -2265,7 +2265,7 @@ QUnit.module('fields', {}, function () { await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'), 'new partner', ['keyup', 'blur']); await testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); - assert.strictEqual($('.modal .modal-body').text().trim(), "Do you want to create new partner as a new Product?"); + assert.strictEqual($('.modal .modal-body').text().trim(), "Create new partner as a new Product?"); form.destroy(); }); @@ -2365,19 +2365,23 @@ QUnit.module('fields', {}, function () { }, }); - // cancel the many2one creation with Cancel button - form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); + // cancel the many2one creation with Discard button + form.$('.o_field_many2one input').focus().val('new product').trigger('input').trigger('keyup'); + await testUtils.nextTick(); + form.$('.o_field_many2one input').trigger('blur'); await testUtils.nextTick(); assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - await testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)')); + await testUtils.dom.click($('.modal .modal-footer .btn:contains(Discard)')); assert.strictEqual($('.modal').length, 0, "the modal should be closed"); assert.strictEqual(form.$('.o_field_many2one input').val(), "", 'the many2one should not set a value as its creation has been cancelled (with Cancel button)'); // cancel the many2one creation with Close button - await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'), - 'new product', ['keyup', 'blur']); + form.$('.o_field_many2one input').focus().val('new product').trigger('input').trigger('keyup'); + await testUtils.nextTick(); + form.$('.o_field_many2one input').trigger('blur'); + await testUtils.nextTick(); assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); await testUtils.dom.click($('.modal .modal-header button')); assert.strictEqual(form.$('.o_field_many2one input').val(), "", @@ -2389,21 +2393,24 @@ QUnit.module('fields', {}, function () { await testUtils.fields.many2one.clickItem('product_id','o'); assert.strictEqual(form.$('.o_field_many2one input').val(), "xphone", "should have selected xphone"); - form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); + form.$('.o_field_many2one input').focus().val('new product').trigger('input').trigger('keyup'); + await testUtils.nextTick(); + form.$('.o_field_many2one input').trigger('blur'); await testUtils.nextTick(); assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - await testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)')); + await testUtils.dom.click($('.modal .modal-footer .btn:contains(Discard)')); assert.strictEqual(form.$('.o_field_many2one input').val(), "xphone", 'should have restored the many2one with its previous selected value (xphone)'); // confirm the many2one creation - form.$('.o_field_many2one input').focus().val('new partner').trigger('keyup').trigger('blur'); + form.$('.o_field_many2one input').focus().val('new product').trigger('input').trigger('keyup'); + await testUtils.nextTick(); + form.$('.o_field_many2one input').trigger('blur'); await testUtils.nextTick(); assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - await testUtils.dom.click($('.modal .modal-footer .btn-primary:contains(Create and edit)')); - await testUtils.nextTick(); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:contains(Create)')); assert.strictEqual($('.modal .o_form_view').length, 1, 'a new modal should be opened and contain a form view'); @@ -2412,6 +2419,28 @@ QUnit.module('fields', {}, function () { form.destroy(); }); + QUnit.test("select a many2one value by focusing out", async function (assert) { + assert.expect(3); + + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: ``, + }); + + form.$('.o_field_many2one input').focus().val('xph').trigger('input').trigger('keyup'); + await testUtils.nextTick(); + form.$('.o_field_many2one input').trigger('blur'); + await testUtils.nextTick(); + + assert.containsNone(document.body, '.modal'); + assert.strictEqual(form.$('.o_field_many2one input').val(), 'xphone'); + assert.containsOnce(form, '.o_external_button'); + + form.destroy(); + }); + QUnit.test('no_create option on a many2one', async function (assert) { assert.expect(1);