From 5a770329859cbc5a1fa49c88f7d449885c7f9d80 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Tue, 30 May 2017 14:54:44 +0200 Subject: [PATCH] [IMP] web: add new "field" field widget Allow to select a field chain associated to a given model in views. This is designed to replace the use of char fields where needed, this commit only does that for the "related" field of the "ir.model.field" view. --- .../web/static/src/js/fields/basic_fields.js | 125 ++++++++++++++++++ .../static/src/js/fields/field_registry.js | 3 +- .../static/src/less/model_field_selector.less | 1 + odoo/addons/base/ir/ir_model_view.xml | 5 +- 4 files changed, 131 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 6392870dc90df..4e93dd8cc3571 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -17,6 +17,7 @@ var Domain = require('web.Domain'); var DomainSelector = require('web.DomainSelector'); var DomainSelectorDialog = require('web.DomainSelectorDialog'); var framework = require('web.framework'); +var ModelFieldSelector = require('web.ModelFieldSelector'); var session = require('web.session'); var utils = require('web.utils'); var view_dialogs = require('web.view_dialogs'); @@ -2339,6 +2340,129 @@ var FieldDomain = AbstractField.extend({ }, }); +/** + * The "Field" field allows the user to construct a field chain for a specific + * model (e.g. user_id.partner_id.name). + */ +var FieldModelField = AbstractField.extend({ + resetOnAnyFieldChange: true, + supportedFieldTypes: ['char'], + custom_events: { + field_chain_changed: '_onFieldChainChange', + }, + + /** + * @constructor + */ + init: function () { + this._super.apply(this, arguments); + + this.fsFilters = this.nodeOptions.fs_filters || {}; + this._setModel(); + }, + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * The field selector internal widget can check if the chain can be used + * with the associated model. + * + * @override + * @returns {boolean} + */ + isValid: function () { + return this._super.apply(this, arguments) + && this.fieldSelector + && this.fieldSelector.isValid(); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Creates the internal field selector widget if not already created (or if + * it was destroyed). Simply changes its value otherwise. + * + * @private + * @override + * @returns {Deferred} + */ + _render: function () { + if (!this._modelName) { + return; + } + + var chain = this.value ? this.value.split('.') : []; + + if (!this.fieldSelector) { + this.fieldSelector = new ModelFieldSelector(this, this._modelName, chain, { + readonly: this.mode === 'readonly', + fs_filters: this.fsFilters, + debugMode: session.debug, + }); + return this.fieldSelector.appendTo(this.$el); + } + + return this.fieldSelector.setChain(chain); + }, + /** + * Checks if the model has changed. The field is set as a + * 'resetOnAnyFieldChange' field so that it can detect if the model field + * it is associated to changes. + * + * @private + * @override + */ + _reset: function () { + this._super.apply(this, arguments); + this._setModel(); + }, + /** + * Checks the model the field must use. It is given by the 'model' node + * options. It is either the name of a model or the name of a field in the + * view which has the model name as value. + * + * Note that if the model name changes, the internal field selector is + * destroyed by this function. So a rerender might be needed after this + * function is called. + * + * @private + */ + _setModel: function () { + var oldModelName = this._modelName; + + // Set model name (either the value of another field or an option) + this._modelName = this.nodeOptions.model; + if (this._modelName in this.recordData) { + this._modelName = this.recordData[this._modelName]; + } + + // Destroy the field selector if the model name has changed + if (this.fieldSelector && this._modelName !== oldModelName) { + this.fieldSelector.destroy(); + delete this.fieldSelector; + } + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Called when the internal field selector widget notifies its changes. + * + * @private + * @param {OdooEvent} ev + */ + _onFieldChainChange: function (ev) { + ev.stopPropagation(); + this._setValue(ev.data.chain.join('.')); + }, +}); + /** * This widget is intended to be used on Text fields. It will provide Ace Editor * for editing XML and Python. @@ -2502,6 +2626,7 @@ return { FieldDate: FieldDate, FieldDateTime: FieldDateTime, FieldDomain: FieldDomain, + FieldModelField: FieldModelField, FieldFloat: FieldFloat, FieldFloatTime: FieldFloatTime, FieldInteger: FieldInteger, diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js index 6692663d5f90f..01c308bed530d 100644 --- a/addons/web/static/src/js/fields/field_registry.js +++ b/addons/web/static/src/js/fields/field_registry.js @@ -6,7 +6,7 @@ var Registry = require('web.Registry'); return new Registry(); }); -odoo.define('web._field_registry', function(require) { +odoo.define('web._field_registry', function (require) { "use strict"; var AbstractField = require('web.AbstractField'); @@ -26,6 +26,7 @@ registry .add('datetime', basic_fields.FieldDateTime) .add('domain', basic_fields.FieldDomain) .add('text', basic_fields.FieldText) + .add('field', basic_fields.FieldModelField) .add('float', basic_fields.FieldFloat) .add('char', basic_fields.FieldChar) .add('link_button', basic_fields.LinkButton) diff --git a/addons/web/static/src/less/model_field_selector.less b/addons/web/static/src/less/model_field_selector.less index 68d6dab32d6a2..400ed04a9106a 100644 --- a/addons/web/static/src/less/model_field_selector.less +++ b/addons/web/static/src/less/model_field_selector.less @@ -8,6 +8,7 @@ .o-align-items(center); height: 100%; min-height: 20px; // needed when there is no value in it and used standalone + &:active, &:focus, &:active:focus { outline: none; } diff --git a/odoo/addons/base/ir/ir_model_view.xml b/odoo/addons/base/ir/ir_model_view.xml index 5e04ac92edaa6..e1fe488519e39 100644 --- a/odoo/addons/base/ir/ir_model_view.xml +++ b/odoo/addons/base/ir/ir_model_view.xml @@ -225,6 +225,7 @@ + @@ -278,7 +279,7 @@ - + @@ -539,7 +540,7 @@ - +