From e26ccdd0b6cc448af26b65a160e3329c4a1e7910 Mon Sep 17 00:00:00 2001 From: Martin Geubelle Date: Tue, 4 Jul 2017 14:14:15 +0200 Subject: [PATCH] [FIX] web: explicit color attribute for m2m_tags Before this fix, the field 'color' was hardcoded in the m2m_tags widget, which means that: - one couldn't specify another field (problem for custom models, with x_...) - if the related model didn't have the field 'color', a warning was raised by the server Now, the color attribute needs to be specified on the widget options if one wants to display colored tags. If the color is not specified, the tags will be displayed in grey. --- .../static/src/js/fields/relational_fields.js | 27 ++++++++----- .../static/src/js/services/data_manager.js | 5 +++ addons/web/static/src/xml/base.xml | 2 +- .../tests/fields/relational_fields_tests.js | 40 +++++++++++++++++-- addons/web/static/tests/views/kanban_tests.js | 2 +- 5 files changed, 61 insertions(+), 15 deletions(-) diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index 4ddc674255a..567c54abcb1 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -1367,7 +1367,6 @@ var FieldMany2ManyTags = AbstractField.extend({ 'click .o_delete': '_onDeleteTag', }), fieldsToFetch: { - color: {type: 'integer'}, display_name: {type: 'char'}, }, @@ -1380,6 +1379,8 @@ var FieldMany2ManyTags = AbstractField.extend({ if (this.mode === 'edit') { this.className += ' o_input'; } + + this.colorField = this.nodeOptions.color_field; }, //-------------------------------------------------------------------------- @@ -1444,6 +1445,7 @@ var FieldMany2ManyTags = AbstractField.extend({ _getRenderTagsContext: function () { var elements = this.value ? _.pluck(this.value.data, 'data') : []; return { + colorField: this.colorField, elements: elements, readonly: this.mode === "readonly", }; @@ -1571,7 +1573,7 @@ var FormFieldMany2ManyTags = FieldMany2ManyTags.extend({ _onOpenColorPicker: function (event) { var tag_id = $(event.currentTarget).data('id'); var tag = _.findWhere(this.value.data, { res_id: tag_id }); - if (tag && 'color' in tag.data) { // if there is a color field on the related model + if (tag && this.colorField in tag.data) { // if there is a color field on the related model this.$color_picker = $(qweb.render('FieldMany2ManyTag.colorpicker', { 'widget': this, 'tag_id': tag_id, @@ -1596,11 +1598,11 @@ var FormFieldMany2ManyTags = FieldMany2ManyTags.extend({ if (color === current_color) { return; } + var changes = {}; + changes[this.colorField] = color; this.trigger_up('field_changed', { dataPointID: _.findWhere(this.value.data, {res_id: id}).id, - changes: { - color: color, - }, + changes: changes, force_save: true, }); }, @@ -1611,12 +1613,19 @@ var KanbanFieldMany2ManyTags = FieldMany2ManyTags.extend({ var self = this; this.$el.empty().addClass('o_field_many2manytags o_kanban_tags'); _.each(this.value.data, function (m2m) { - // 10th color is invisible - if ('color' in m2m.data && m2m.data.color !== 10) { - $('') - .addClass('o_tag o_tag_color_' + m2m.data.color) + var $tag = $('') .attr('title', _.str.escapeHTML(m2m.data.display_name)) .appendTo(self.$el); + if (self.colorField in m2m.data) { + if (m2m.data[self.colorField] === 10) { + // 10th color is invisible + $tag.hide(); + } else { + $tag.addClass('o_tag o_tag_color_' + m2m.data[self.colorField]); + } + } else { + // display tags in grey by default + $tag.addClass('o_tag o_tag_color_0'); } }); }, diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index 41fc293e383..c1e69a72ce3 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -355,6 +355,11 @@ return core.Class.extend({ return {}; }), }; + if (attrs.options.color_field) { + // used by m2m tags + attrs.relatedFields[attrs.options.color_field] = { type: 'integer' }; + attrs.fieldsInfo.default[attrs.options.color_field] = {}; + } } } return attrs; diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 06e6b8b2285..80d40404f28 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -759,7 +759,7 @@ - + diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index 5c2a93ee775..d4d3a6307f9 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -6017,8 +6017,37 @@ QUnit.module('relational_fields', { QUnit.module('FieldMany2ManyTags'); - QUnit.test('fieldmany2many tags: rendering and edition', function (assert) { - assert.expect(17); + QUnit.test('fieldmany2many tags without color', function (assert) { + assert.expect(4); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'
' + + '' + + '', + 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"); + } + return this._super.apply(this, arguments); + } + }); + var $input = form.$('.o_field_many2manytags 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, + "should contain 1 tag"); + assert.ok(form.$('.o_field_many2manytags > span:contains("gold")').length, + "should contain newly added tag 'gold'"); + form.destroy(); + }); + + QUnit.test('fieldmany2many tags with color: rendering and edition', function (assert) { + assert.expect(20); this.data.partner.records[0].timmy = [12, 14]; this.data.partner_type.records.push({id: 13, display_name: "red", color: 8}); @@ -6027,7 +6056,7 @@ QUnit.module('relational_fields', { model: 'partner', data: this.data, arch:'
' + - '' + + '' + '', res_id: 1, mockRPC: function (route, args) { @@ -6038,6 +6067,9 @@ QUnit.module('relational_fields', { assert.ok(_.isEqual(_.sortBy(commands[0][2], _.identity.bind(_)), [12, 13]), "new value should be [12, 13]"); } + if (args.method ==='read' && args.model === 'partner_type') { + assert.deepEqual(args.args[1], ['display_name', 'color'], "should read the color field"); + } return this._super.apply(this, arguments); }, }); @@ -6183,7 +6215,7 @@ QUnit.module('relational_fields', { model: 'partner', data: this.data, arch:'
' + - '' + + '' + '', res_id: 1, }); diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index e8ebae3d6be..f3a653113ec 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -445,7 +445,7 @@ QUnit.module('Views', { arch: '' + '' + '
' + - '' + + '' + '' + '' + '
' +