diff options
| author | qsm-odoo <qsm@odoo.com> | 2017-03-08 16:43:44 +0100 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2017-04-11 19:44:38 +0200 |
| commit | 29cd7154e66a30fb656b88e16b4301d17fa7d958 (patch) | |
| tree | 4f1adf4c812aa38a1a9029c4e13d0beac26b45ee /addons/web/static/src | |
| parent | b5b649e5b21d41279f12f0dbe6cfa53ca2c52580 (diff) | |
[FIX] web: restore FieldStatus behavior
FieldStatus was broken:
- With a selection, the statusbar_visible attribute forces the choices
to display, the discarded ones do not appear at all (even folded)
- With a m2o, the fold_field option tells the field to check in the
relation to know if the choice has to be folded or not, this was not
properly supported
- Changing a m2o value was broken as the parseMany2one function did
not exist
- The status were misordered
- ...
* Also refactor the way the rendering is handled.
* Also modify all statusbar tests so that the statusbar widget is
placed in the form header tag (as it is the common use case).
Diffstat (limited to 'addons/web/static/src')
| -rw-r--r-- | addons/web/static/src/js/fields/field_utils.js | 30 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/relational_fields.js | 85 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_model.js | 9 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/form/form_renderer.js | 7 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 25 |
5 files changed, 90 insertions, 66 deletions
diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js index c359a014b4e..406a86ac7a2 100644 --- a/addons/web/static/src/js/fields/field_utils.js +++ b/addons/web/static/src/js/fields/field_utils.js @@ -336,6 +336,34 @@ function parseMonetary(formatted_value) { return parseFloat(value); } +/** + * Creates an object with id and display_name. + * + * @param {Array|number|string|Object} value + * The given value can be : + * - an array with id as first element and display_name as second element + * - a number or a string representing the id (the display_name will be + * returned as undefined) + * - an object, simply returned untouched + * @returns {Object} (contains the id and display_name) + * Note: if the given value is not an array, a string or a + * number, the value is returned untouched. + */ +function parseMany2one(value) { + if (_.isArray(value)) { + return { + id: value[0], + display_name: value[1], + }; + } + if (_.isNumber(value) || _.isString(value)) { + return { + id: parseInt(value, 10), + }; + } + return value; +} + return { format: { binary: _.identity, // todo @@ -368,7 +396,7 @@ return { id: _.identity, integer: parseInteger, many2many: _.identity, // todo - many2one: _.identity, + many2one: parseMany2one, monetary: parseMonetary, one2many: _.identity, reference: _.identity, // todo diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index 68bd7a52343..4663c40f755 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -1166,13 +1166,15 @@ var FieldMany2ManyCheckBoxes = AbstractField.extend({ //------------------------------------------------------------------------------ var FieldStatus = AbstractField.extend({ - template: "FieldStatus", className: 'o_statusbar_status', events: { - 'click .o_arrow_button': '_onClickStage', + 'click button:not(.dropdown-toggle)': '_onClickStage', }, specialData: "_fetchSpecialStatus", supportedFieldTypes: ['selection', 'many2one'], + /** + * @override init from AbstractField + */ init: function () { this._super.apply(this, arguments); this._setState(); @@ -1183,6 +1185,7 @@ var FieldStatus = AbstractField.extend({ //-------------------------------------------------------------------------- /** + * @override _reset from AbstractField * @private */ _reset: function () { @@ -1190,45 +1193,51 @@ var FieldStatus = AbstractField.extend({ this._setState(); }, /** + * Prepares the rendering data from the field and record data. * @private */ _setState: function () { + var self = this; if (this.field.type === 'many2one') { - this.status_information = this.record.specialData[this.name]; - var status = _.findWhere(this.status_information, {id: this.value.res_id}); - if (status) { - status.selected = true; - } + this.status_information = _.map(this.record.specialData[this.name], function (info) { + return _.extend({ + selected: info.id === self.value.res_id, + }, info); + }); } else { - var self = this; - this.status_information = _.map(this.field.selection, function (val) { - return { id: val[0], display_name: val[1], selected: val[0] === self.value }; + var selection = this.field.selection; + if (this.attrs.statusbar_visible) { + var restriction = this.attrs.statusbar_visible.split(","); + selection = _.filter(selection, function (val) { + return _.contains(restriction, val[0]) || val[0] === self.value; + }); + } + this.status_information = _.map(selection, function (val) { + return { id: val[0], display_name: val[1], selected: val[0] === self.value, fold: false }; }); } }, /** + * @override _render from AbstractField * @private */ _render: function () { - var visible = this.attrs.statusbar_visible; - var selection_folded = []; - var selection_unfolded = []; - _.each(this.status_information, function (info) { - if (info.selected && (info.fold || visible && visible.indexOf(info.display_name) === -1)) { - selection_folded.push(info); - } else { - selection_unfolded.push(info); - } - }); - var mobile = config.device.size_class <= config.device.SIZES.XS; - // grep: FieldStatus.content.mobile, FieldStatus.content.desktop - var content = qweb.render("FieldStatus.content." + (mobile ? 'mobile' : 'desktop'), { - selection_folded: selection_folded.reverse(), - selection_unfolded: selection_unfolded.reverse(), - clickable: !!this.attrs.clickable, - }); - this.$el.html(content); - this.$('.disabled').prop('disabled', true); + if (config.device.size_class > config.device.SIZES.XS) { + var selections = _.partition(this.status_information, function (info) { + return (info.selected || !info.fold); + }); + this.$el.html(qweb.render("FieldStatus.content.desktop", { + selection_unfolded: selections[0], + selection_folded: selections[1], + clickable: !!this.attrs.clickable, + })); + } else { + this.$el.html(qweb.render("FieldStatus.content.mobile", { + selection: this.status_information, + value: _.findWhere(this.status_information, {selected: true}).display_name, + clickable: !!this.attrs.clickable, + })); + } }, //-------------------------------------------------------------------------- @@ -1236,22 +1245,14 @@ var FieldStatus = AbstractField.extend({ //-------------------------------------------------------------------------- /** - * Note that this function is debounced... + * Called when on status stage is clicked -> sets the field value. + * Note: this function is debounced... * * @private - * @param {MouseEvent} event + * @param {MouseEvent} e */ - _onClickStage: _.debounce(function (event) { - var $stage = $(event.currentTarget); - var val; - if (this.field.type === "many2one") { - val = parseInt($stage.data("value"), 10); - } else { - val = $stage.data("value"); - } - if (val) { - this._setValue(val); - } + _onClickStage: _.debounce(function (e) { + this._setValue($(e.currentTarget).data("value")); }, 300, true), }); 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 cdb8bb61f7c..afac5c1c5ff 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -964,7 +964,7 @@ var BasicModel = AbstractModel.extend({ } var rel_data = _.pick(data, 'id', 'display_name'); var def; - if (!('display_name' in rel_data)) { + if (rel_data.display_name === undefined) { var field = record.fields[fieldName]; def = this._rpc(field.relation, 'name_get') .args([data.id]) @@ -1498,7 +1498,12 @@ var BasicModel = AbstractModel.extend({ _fetchSpecialStatus: function (record, fieldName) { var foldField = record.fieldAttrs[fieldName].options.fold_field; var fieldsToRead = foldField ? [foldField] : []; - return this._fetchSpecialMany2ones(record, fieldName, fieldsToRead); + return this._fetchSpecialMany2ones(record, fieldName, fieldsToRead).then(function (m2os) { + _.each(m2os, function (m2o) { + m2o.fold = foldField ? m2o[foldField] : false; + }); + return m2os; + }); }, /** * Fetch all data in a ungrouped list 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 a83c7d653b5..ce7c3b0bc16 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -477,14 +477,13 @@ return BasicRenderer.extend({ }, _renderTagHeader: function (node) { var self = this; - var $statusbar = $('<div>').addClass('o_form_statusbar'); - var $buttons = $('<div>').addClass('o_statusbar_buttons'); + var $statusbar = $('<div>', {class: 'o_form_statusbar'}); + var $buttons = $('<div>', {class: 'o_statusbar_buttons'}); $statusbar.append($buttons); _.each(node.children, function (child) { if (child.tag === 'button') { $buttons.append(self._renderHeaderButton(child)); - } - if (child.tag === 'field') { + } else if (child.tag === 'field') { var widget = self._renderFieldWidget(child); $statusbar.append(widget.$el); } diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 1f95503441a..3976a41d783 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -926,13 +926,7 @@ <span t-if="widget.string"><t t-esc="widget.string"/></span> </div> </t> -<t t-name="FieldStatus"> - <ul class="o_statusbar_status" t-att-style="widget.attrs.style"/> -</t> <t t-name="FieldStatus.content.desktop"> - <t t-foreach="selection_unfolded" t-as="i"> - <t t-call="FieldStatus.content.button"/> - </t> <t t-if="selection_folded.length"> <ul class="dropdown-menu o-status-more" role="menu"> <li t-foreach="selection_folded" t-as="i"> @@ -941,27 +935,24 @@ </ul> <button type="button" class="btn btn-sm o_arrow_button btn-default dropdown-toggle" data-toggle="dropdown">More <span class="caret"/></button> </t> + <t t-foreach="selection_unfolded.reverse()" t-as="i"> + <t t-call="FieldStatus.content.button"/> + </t> </t> <t t-name="FieldStatus.content.mobile"> <button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown"> - <t t-foreach="selection_unfolded" t-as="i"> - <t t-if="i.id === value"> - <t t-esc="i.display_name"/> - </t> - </t> + <t t-esc="value"/> </button> <ul class="dropdown-menu o-status-more" role="menu"> - <li t-foreach="selection_unfolded" t-as="i"> - <t t-call="FieldStatus.content.button"/> - </li> - <li t-foreach="selection_folded" t-as="i"> + <li t-foreach="selection" t-as="i"> <t t-call="FieldStatus.content.button"/> </li> </ul> </t> <t t-name="FieldStatus.content.button"> - <button type="button" t-att-data-value="i.id" - t-attf-class="btn btn-sm o_arrow_button #{i.selected ? 'btn-primary disabled' : 'btn-default'} #{!clickable ? 'disabled' : ''}"> + <t t-set="disabled" t-value="!clickable || i.selected"/> + <button type="button" t-att-data-value="i.id" t-att-disabled="disabled ? 'disabled' : undefined" + t-attf-class="btn btn-sm o_arrow_button btn-#{i.selected ? 'primary' : 'default'}#{disabled ? ' disabled' : ''}"> <t t-esc="i.display_name"/> </button> </t> |
