diff options
| author | Christophe Simonis <chs@odoo.com> | 2017-07-26 23:35:06 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2017-07-26 23:35:06 +0200 |
| commit | 8a1311bca17bd93a87f94579698adddc416f78f0 (patch) | |
| tree | bac0ac044fd643927466dc5eb32d0359d9b37bde /addons/web/static | |
| parent | faf72250221e0eb2fc711b9168c75b1dc70120e7 (diff) | |
| parent | 3d4238f71e48de14afd0072a8309f2bb6fc46eb6 (diff) | |
[MERGE] forward port branch saas-17 up to 3d4238f71e4
Diffstat (limited to 'addons/web/static')
| -rw-r--r-- | addons/web/static/src/js/chrome/search_menus.js | 8 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome/search_view.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/relational_fields.js | 34 | ||||
| -rw-r--r-- | addons/web/static/src/js/services/data_manager.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_model.js | 36 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/form/form_renderer.js | 15 | ||||
| -rw-r--r-- | addons/web/static/src/less/form_view.less | 21 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 49 | ||||
| -rw-r--r-- | addons/web/static/tests/fields/relational_fields_tests.js | 72 | ||||
| -rw-r--r-- | addons/web/static/tests/helpers/mock_server.js | 2 | ||||
| -rw-r--r-- | addons/web/static/tests/views/basic_model_tests.js | 14 | ||||
| -rw-r--r-- | addons/web/static/tests/views/form_tests.js | 65 |
12 files changed, 260 insertions, 60 deletions
diff --git a/addons/web/static/src/js/chrome/search_menus.js b/addons/web/static/src/js/chrome/search_menus.js index 1da7800b049..eee7303ffbd 100644 --- a/addons/web/static/src/js/chrome/search_menus.js +++ b/addons/web/static/src/js/chrome/search_menus.js @@ -122,6 +122,7 @@ return Widget.extend({ model_id: this.target_model, context: results.context, domain: results.domain, + sort: JSON.stringify(this.searchview.dataset._sort), is_default: default_filter, action_id: this.action_id, }; @@ -243,6 +244,13 @@ return Widget.extend({ } this.query.reset([this.facet_for(filter)], { preventSearch: preventSearch || false}); + + // Load sort settings on view + if (!_.isUndefined(filter.sort)){ + var sort_items = JSON.parse(filter.sort); + this.searchview.dataset.set_sort(sort_items); + } + this.$filters[this.key_for(filter)].addClass('selected'); }, remove_filter: function (filter, $filter, key) { diff --git a/addons/web/static/src/js/chrome/search_view.js b/addons/web/static/src/js/chrome/search_view.js index 26305817e55..6c3adcafcca 100644 --- a/addons/web/static/src/js/chrome/search_view.js +++ b/addons/web/static/src/js/chrome/search_view.js @@ -232,7 +232,7 @@ var SearchView = Widget.extend({ 'click .o_searchview_more': function (e) { $(e.target).toggleClass('fa-search-plus fa-search-minus'); var visibleSearchMenu = this.call('local_storage', 'getItem', 'visible_search_menu'); - this.call('local_storage', 'setItem', visibleSearchMenu !== 'true'); + this.call('local_storage', 'setItem', 'visible_search_menu', visibleSearchMenu !== 'true'); this.toggle_buttons(); }, 'keydown .o_searchview_input, .o_searchview_facet': function (e) { diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index 7522bb3bc37..1935e5804dd 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -99,7 +99,7 @@ var FieldMany2One = AbstractField.extend({ this.nodeOptions = _.defaults(this.nodeOptions, { quick_create: true, }); - this.m2o_value = field_utils.format.many2one(this.value); + this.m2o_value = this._formatValue(this.value); // 'recordParams' is a dict of params used when calling functions // 'getDomain' and 'getContext' on this.record this.recordParams = {fieldName: this.name, viewType: this.viewType}; @@ -838,8 +838,10 @@ var FieldX2Many = AbstractField.extend({ */ _onDeleteRecord: function (ev) { ev.stopPropagation(); + var shouldForget = this.attrs.widget === 'many2many' || this.field.type === 'many2many'; + var operation = shouldForget ? 'FORGET' : 'DELETE'; this._setValue({ - operation: 'REMOVE', + operation: operation, ids: [ev.data.id], }); }, @@ -1290,7 +1292,7 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({ var record = _.findWhere(this.value.data, {res_id: fileID}); if (record) { this._setValue({ - operation: 'REMOVE', + operation: 'FORGET', ids: [record.id], }); var metadata = this.metadata[record.id]; @@ -1469,7 +1471,7 @@ var FieldMany2ManyTags = AbstractField.extend({ _removeTag: function (id) { var record = _.findWhere(this.value.data, {res_id: id}); this._setValue({ - operation: 'REMOVE', + operation: 'FORGET', ids: [record.id], }); }, @@ -2029,7 +2031,20 @@ var FieldReference = FieldMany2One.extend({ // needs to be copied as it is an unmutable object this.field = _.extend({}, this.field); if (this.value) { - this._setRelation(this.value.model); + var model = null; + // The value of a Reference field can either be a string in the form + // of model,record_id or an object + if (typeof this.value === "string") { + var value = this.value.split(','); + model = value[0]; + this.value = { + res_id: parseInt(value[1]), + }; + } else { + model = this.value.model; + } + + this._setRelation(model); } }, /** @@ -2045,6 +2060,15 @@ var FieldReference = FieldMany2One.extend({ //-------------------------------------------------------------------------- /** + * Get the encompassing record's display_name + * + * @override + */ + _formatValue: function () { + return this.recordData.display_name; + }, + + /** * Add a select in edit mode (for the model). * * @override diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index c1e69a72ce3..999a9d8df01 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -349,7 +349,7 @@ return core.Class.extend({ } if (attrs.Widget.prototype.fieldsToFetch) { attrs.viewType = 'default'; - attrs.relatedFields = attrs.Widget.prototype.fieldsToFetch; + attrs.relatedFields = _.extend({}, attrs.Widget.prototype.fieldsToFetch); attrs.fieldsInfo = { default: _.mapObject(attrs.Widget.prototype.fieldsToFetch, function () { return {}; diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 75a0ad02971..8f679207f00 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -509,6 +509,7 @@ var BasicModel = AbstractModel.extend({ } if (params.type === 'record' && params.res_id === undefined) { + params.allowWarning = true; return this._makeDefaultRecord(params.modelName, params); } var dataPoint = this._makeDataPoint(params); @@ -1294,9 +1295,12 @@ var BasicModel = AbstractModel.extend({ defs.push(this._applyChange(command.id, command.data)); } break; - case 'REMOVE': + case 'FORGET': + // Unlink the record of list. + list._forceM2MUnlink = true; + case 'DELETE': // filter out existing operations involving the current - // dataPoint, and add a 'REMOVE' operation only if there is + // dataPoint, and add a 'DELETE' or 'FORGET' operation only if there is // no 'ADD' operation for that dataPoint, as it would mean // that the record wasn't in the relation yet var idsToRemove = command.ids; @@ -1308,7 +1312,8 @@ var BasicModel = AbstractModel.extend({ return idInCommands; }); _.each(idsToRemove, function (id) { - list._changes.push({operation: 'REMOVE', id: id}); + var operation = list._forceM2MUnlink ? 'FORGET': 'DELETE'; + list._changes.push({operation: operation, id: id}); }); break; case 'REPLACE_WITH': @@ -1332,7 +1337,7 @@ var BasicModel = AbstractModel.extend({ return self.localData[localId]; }); removedDef = this._applyX2ManyChange(record, fieldName, { - operation: 'REMOVE', + operation: 'DELETE', ids: _.map(removedIds, function (resID) { return _.findWhere(listData, {res_id: resID}).id; }), @@ -1349,7 +1354,7 @@ var BasicModel = AbstractModel.extend({ }, /** * In dataPoints of type list for x2manys, the changes are stored as a list - * of operations (being of type 'ADD', 'REMOVE', 'UPDATE' or 'REMOVE_ALL'). + * of operations (being of type 'ADD', 'DELETE', 'FORGET', UPDATE' or 'REMOVE_ALL'). * This function applies the operation of such a dataPoint without altering * the original dataPoint. It returns a copy of the dataPoint in which the * 'count', 'data' and 'res_ids' keys have been updated. @@ -1383,7 +1388,8 @@ var BasicModel = AbstractModel.extend({ list.res_ids.push(resID); } break; - case 'REMOVE': + case 'FORGET': + case 'DELETE': list.count--; list.res_ids = _.without(list.res_ids, relRecord.res_id); break; @@ -2348,7 +2354,11 @@ var BasicModel = AbstractModel.extend({ } // add delete commands for (i = 0; i < removedIds.length; i++) { - commands[fieldName].push(x2ManyCommands.delete(removedIds[i])); + if (list._forceM2MUnlink) { + commands[fieldName].push(x2ManyCommands.forget(removedIds[i])); + } else { + commands[fieldName].push(x2ManyCommands.delete(removedIds[i])); + } } } } @@ -2601,7 +2611,9 @@ var BasicModel = AbstractModel.extend({ var isValid = true; var element = this.localData[id]; _.each(element._changes, function (command) { - if (command.operation === 'REMOVE' || command.operation === 'REMOVE_ALL') { + if (command.operation === 'DELETE' || + command.operation === 'FORGET' || + command.operation === 'REMOVE_ALL') { return; } var recordData = self.get(command.id, {raw: true}).data; @@ -2735,6 +2747,8 @@ var BasicModel = AbstractModel.extend({ * @private * @param {any} params * @param {string} modelName model name + * @param {boolean} [params.allowWarning=false] if true, the default record + * operation can complete, even if a warning is raised * @param {Object} params.context the context for the new record * @param {Object} params.fieldsInfo contains the fieldInfo of each view, * for each field @@ -2887,7 +2901,11 @@ var BasicModel = AbstractModel.extend({ .then(function () { return self._performOnChange(record, fields_key).then(function () { if (record._warning) { - return $.Deferred().reject(); + if (params.allowWarning) { + delete record._warning; + } else { + return $.Deferred().reject(); + } } }); }) diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 08b3fabd2e2..35194b313ad 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -336,12 +336,27 @@ var FormRenderer = BasicRenderer.extend({ * @returns {jQueryElement} */ _renderHeaderButton: function (node) { + var self = this; var $button = $('<button>') .text(node.attrs.string) .addClass('btn btn-sm btn-default'); this._addOnClickAction($button, node); this._handleAttributes($button, node); this._registerModifiers(node, this.state, $button); + + // Display tooltip + if (config.debug || node.attrs.help) { + $button.tooltip({ + delay: { show: 1000, hide: 0 }, + title: function () { + return qweb.render('WidgetButton.tooltip', { + debug: config.debug, + state: self.state, + node: node, + }); + }, + }); + } return $button; }, /** diff --git a/addons/web/static/src/less/form_view.less b/addons/web/static/src/less/form_view.less index 3127b2e4ea7..bcea630b152 100644 --- a/addons/web/static/src/less/form_view.less +++ b/addons/web/static/src/less/form_view.less @@ -86,18 +86,19 @@ display: inline-block; } - .o_form_uri { // FIXME maybe global? - display: inline-block; + } - color: @odoo-main-text-color; + .o_form_uri { + display: inline-block; + + color: @odoo-main-text-color; + &:first-line { + color: @link-color; + } + &:hover { + color: darken(@odoo-main-text-color, 1%); // hack required on chrome &:first-line { - color: @link-color; - } - &:hover { - color: darken(@odoo-main-text-color, 1%); // hack required on chrome - &:first-line { - color: darken(@link-color, 15%); - } + color: darken(@link-color, 15%); } } } diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index b9aa125c8de..f0a08b5dc62 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -69,36 +69,49 @@ </li> </ul> </t> -<t t-name="WidgetButton.tooltip" t-extend="WidgetLabel.tooltip"> - <t t-jquery="div.oe_tooltip_string" t-operation="replace"> - <div class="oe_tooltip_string" t-if="debug || widget.string"> - <t t-if="debug"> - Button - <t t-if="widget.string">: </t> - <t t-if="!widget.string"> (no string)</t> - </t> - <t t-esc="widget.string"/> - </div> - </t> - <t t-jquery="ul.oe_tooltip_technical" t-operation="append"> - <li t-if="widget.node.attrs.special" data-item="special"> +<t t-name="WidgetButton.tooltip"> + <div class="oe_tooltip_string" t-if="debug || node.attrs.string"> + <t t-if="debug"> + Button + <t t-if="node.attrs.string">: </t> + <t t-if="!node.attrs.string"> (no string)</t> + </t> + <t t-esc="node.attrs.string"/> + </div> + <p t-if="node.attrs.help" class="oe_tooltip_help"> + <t t-esc="node.attrs.help"/> + </p> + <ul t-if="debug" class="oe_tooltip_technical"> + <li data-item="object"> + <span class="oe_tooltip_technical_title">Object:</span> + <t t-esc="state.model"/> + </li> + <li t-if="node.attrs.context" data-item="context"> + <span class="oe_tooltip_technical_title">Context:</span> + <t t-esc="node.attrs.context || widget.field.context"/> + </li> + <li t-if="node.attrs.modifiers and node.attrs.modifiers != '{}'" data-item="modifiers"> + <span class="oe_tooltip_technical_title">Modifiers:</span> + <t t-esc="node.attrs.modifiers"/> + </li> + <li t-if="node.attrs.special" data-item="special"> <span class="oe_tooltip_technical_title">Special:</span> - <t t-esc="widget.node.attrs.special"/> + <t t-esc="node.attrs.special"/> </li> - <t t-set="button_type" t-value="widget.node.attrs.type"/> + <t t-set="button_type" t-value="node.attrs.type"/> <li t-if="button_type" data-item="button_type"> <span class="oe_tooltip_technical_title">Button Type:</span> <t t-esc="button_type"/> </li> <li t-if="button_type === 'object'" data-item="button_method"> <span class="oe_tooltip_technical_title">Method:</span> - <t t-esc="widget.node.attrs.name"/> + <t t-esc="node.attrs.name"/> </li> <li t-if="button_type === 'action'" data-item="button_action"> <span class="oe_tooltip_technical_title">Action ID:</span> - <t t-esc="widget.node.attrs.name"/> + <t t-esc="node.attrs.name"/> </li> - </t> + </ul> </t> <t t-name="Notification"> diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index 1a7badd353f..68a0257b24c 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -2005,6 +2005,49 @@ QUnit.module('relational_fields', { form.destroy(); }); + QUnit.test('one2many list: unlink one record', function (assert) { + assert.expect(5); + this.data.partner.records[0].p = [2, 4]; + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'<form string="Partners">' + + '<field name="p" widget="many2many">' + + '<tree>' + + '<field name="display_name"/>' + + '</tree>' + + '</field>' + + '</form>', + res_id: 1, + mockRPC: function (route, args) { + if (route === '/web/dataset/call_kw/partner/write') { + var commands = args.args[1].p; + assert.strictEqual(commands.length, 2, + 'should have generated two commands'); + assert.ok(commands[0][0] === 4 && commands[0][1] === 4, + 'should have generated the command 4 (LINK_TO) with id 4'); + assert.ok(commands[1][0] === 3 && commands[1][1] === 2, + 'should have generated the command 3 (UNLINK) with id 2'); + } + return this._super.apply(this, arguments); + }, + }); + form.$buttons.find('.o_form_button_edit').click(); + + assert.strictEqual(form.$('td.o_list_record_delete span').length, 2, + "should have 2 delete buttons"); + + form.$('td.o_list_record_delete span').first().click(); + + assert.strictEqual(form.$('td.o_list_record_delete span').length, 1, + "should have 1 delete button (a record is supposed to have been unlinked)"); + + // save and check that the correct command has been generated + form.$buttons.find('.o_form_button_save').click(); + form.destroy(); + }); + QUnit.test('one2many list: deleting one record', function (assert) { assert.expect(5); this.data.partner.records[0].p = [2, 4]; @@ -6156,32 +6199,44 @@ QUnit.module('relational_fields', { QUnit.module('FieldMany2ManyTags'); - QUnit.test('fieldmany2many tags without color', function (assert) { - assert.expect(4); + QUnit.test('fieldmany2many tags with and without color', function (assert) { + assert.expect(5); + this.data.partner.fields.partner_ids = {string: "Partner", type: "many2many", relation: 'partner'}; var form = createView({ View: FormView, model: 'partner', data: this.data, arch:'<form string="Partners">' + + '<field name="partner_ids" widget="many2many_tags" options="{\'color_field\': \'color\'}"/>' + '<field name="timmy" widget="many2many_tags"/>' + '</form>', mockRPC: function (route, args) { if (args.method ==='read' && args.model === 'partner_type') { assert.deepEqual(args.args , [[12], ['display_name']], "should not read any color field"); + } else if (args.method ==='read' && args.model === 'partner') { + assert.deepEqual(args.args , [[1], ['display_name', 'color']], "should read color field"); } return this._super.apply(this, arguments); } }); - var $input = form.$('.o_field_many2manytags input'); + + // add a tag on field partner_ids + var $input = form.$('.o_field_many2manytags[name="partner_ids"] input'); + $input.click(); // opens the dropdown + $input.autocomplete('widget').find('li:first()').click(); // adds a tag + + // add a tag on field timmy + $input = form.$('.o_field_many2manytags[name="timmy"] input'); $input.click(); // opens the dropdown assert.strictEqual($input.autocomplete('widget').find('li').length, 3, "autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')"); $input.autocomplete('widget').find('li:first()').click(); // adds a tag - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 1, + assert.strictEqual(form.$('.o_field_many2manytags[name="timmy"] > span').length, 1, "should contain 1 tag"); - assert.ok(form.$('.o_field_many2manytags > span:contains("gold")').length, + assert.ok(form.$('.o_field_many2manytags[name="timmy"] > span:contains("gold")').length, "should contain newly added tag 'gold'"); + form.destroy(); }); @@ -6909,7 +6964,7 @@ QUnit.module('relational_fields', { "should do a do_action with correct parameters"); }); - assert.strictEqual(form.$('a.o_form_uri:contains(xphone)').length, 1, + assert.strictEqual(form.$('a.o_form_uri:contains(first record)').length, 1, "should contain a link"); form.$('a.o_form_uri').click(); // click on the link in readonly mode (should trigger do_action) @@ -6921,7 +6976,7 @@ QUnit.module('relational_fields', { "should contain one many2one"); assert.strictEqual(form.$('.o_field_widget select').val(), "product", "widget should contain one select with the model"); - assert.strictEqual(form.$('.o_field_widget input').val(), "xphone", + assert.strictEqual(form.$('.o_field_widget input').val(), "first record", "widget should contain one input with the record"); var options = _.map(form.$('.o_field_widget select > option'), function (el) { @@ -6930,7 +6985,6 @@ QUnit.module('relational_fields', { assert.deepEqual(options, ['', 'product', 'partner_type', 'partner'], "the options should be correctly set"); - form.$('.o_external_button').click(); // click on the external button (should do an RPC) assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: custom label', @@ -6947,7 +7001,7 @@ QUnit.module('relational_fields', { $dropdown.find('li:first()').click(); form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('a.o_form_uri:contains(gold)').length, 1, + assert.strictEqual(form.$('a.o_form_uri').length, 1, "should contain a link with the new value"); form.destroy(); diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js index 06b85dd8f9e..3f97df1d4bf 100644 --- a/addons/web/static/tests/helpers/mock_server.js +++ b/addons/web/static/tests/helpers/mock_server.js @@ -947,6 +947,8 @@ var MockServer = Class.extend({ self._mockWrite(field.relation, [[command[1]], command[2]]); } else if (command[0] === 2) { // DELETE ids = _.without(ids, command[1]); + } else if (command[0] === 3) { // FORGET + ids = _.without(ids, command[1]); } else if (command[0] === 4) { // LINK_TO if (!_.contains(ids, command[1])) { ids.push(command[1]); diff --git a/addons/web/static/tests/views/basic_model_tests.js b/addons/web/static/tests/views/basic_model_tests.js index 7f7547262da..9e8e64edde6 100644 --- a/addons/web/static/tests/views/basic_model_tests.js +++ b/addons/web/static/tests/views/basic_model_tests.js @@ -361,27 +361,27 @@ QUnit.module('Views', { assert.strictEqual(record.data.product_ids.count, 2, "there should be two records in the relation"); - // trigger a 'REMOVE' command on the existing record + // trigger a 'DELETE' command on the existing record var existingRecordID = record.data.product_ids.data[0].id; - model.notifyChanges(resultID, {product_ids: {operation: 'REMOVE', ids: [existingRecordID]}}); + model.notifyChanges(resultID, {product_ids: {operation: 'DELETE', ids: [existingRecordID]}}); assert.deepEqual(model.localData[x2mListID]._changes, [{ operation: 'ADD', id: newRecordID, }, { operation: 'UPDATE', id: newRecordID, }, { - operation: 'REMOVE', id: existingRecordID, + operation: 'DELETE', id: existingRecordID, }], "_changes should be correct"); record = model.get(resultID); assert.strictEqual(record.data.product_ids.count, 1, "there should be one record in the relation"); - // trigger a 'REMOVE' command on the new record - model.notifyChanges(resultID, {product_ids: {operation: 'REMOVE', ids: [newRecordID]}}); + // trigger a 'DELETE' command on the new record + model.notifyChanges(resultID, {product_ids: {operation: 'DELETE', ids: [newRecordID]}}); assert.deepEqual(model.localData[x2mListID]._changes, [{ - operation: 'REMOVE', id: existingRecordID, + operation: 'DELETE', id: existingRecordID, }], "_changes should be correct"); record = model.get(resultID); assert.strictEqual(record.data.product_ids.count, 0, @@ -827,7 +827,7 @@ QUnit.module('Views', { assert.ok(_.isObject(category_value), "category field should have been fetched"); assert.strictEqual(category_value.data.length, 1, "category field should contain one record"); model.notifyChanges(resultID, {category: { - operation: 'REMOVE', + operation: 'DELETE', ids: [category_value.data[0].id], }}); assert.ok(model.isDirty(resultID), "record should be considered dirty"); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 8a718ce01ec..4b499fe1c6f 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -2,6 +2,7 @@ odoo.define('web.form_tests', function (require) { "use strict"; var concurrency = require('web.concurrency'); +var config = require('web.config'); var core = require('web.core'); var FormView = require('web.FormView'); var pyeval = require('web.pyeval'); @@ -2561,6 +2562,42 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('can create record even if onchange returns a warning', function (assert) { + assert.expect(2); + + this.data.partner.onchanges = { foo: true }; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<group><field name="foo"/><field name="int_field"/></group>' + + '</form>', + mockRPC: function (route, args) { + if (args.method === 'onchange') { + return $.when({ + value: { int_field: 10 }, + warning: { + title: "Warning", + message: "You must first select a partner" + } + }); + } + return this._super.apply(this, arguments); + }, + intercepts: { + warning: function (event) { + assert.step('warning'); + }, + }, + }); + assert.strictEqual(form.$('input[name="int_field"]').val(), "10", + "record should have been created and rendered"); + + form.destroy(); + }); + QUnit.test('do nothing if add a line in one2many result in a onchange with a warning', function (assert) { assert.expect(2); @@ -5389,6 +5426,34 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('display tooltips for buttons', function (assert) { + assert.expect(1); + + var initialDebugMode = config.debug; + config.debug = true; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<header>' + + '<button name="some_method" class="oe_highlight" string="Button" type="object"/>' + + '</header>' + + '</form>', + }); + + var $button = form.$('.o_form_statusbar button'); + $button.tooltip('show', false); + $button.trigger($.Event('mouseenter')); + + assert.strictEqual($('.tooltip .oe_tooltip_string').length, 1, + "should have rendered a tooltip"); + + config.debug = initialDebugMode; + form.destroy(); + }); + QUnit.test('rainbowman attributes correctly passed on button click', function (assert) { assert.expect(1); |
