summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/fields
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/static/src/js/fields')
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js155
1 files changed, 81 insertions, 74 deletions
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index 705a0c872fa..667c2a1b6ca 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -16,7 +16,7 @@ odoo.define('web.relational_fields', function (require) {
var AbstractField = require('web.AbstractField');
var basicFields = require('web.basic_fields');
var concurrency = require('web.concurrency');
-var ControlPanelView = require('web.ControlPanelView');
+const ControlPanelX2Many = require('web.ControlPanelX2Many');
var core = require('web.core');
var data = require('web.data');
var Dialog = require('web.Dialog');
@@ -26,7 +26,7 @@ const Domain = require('web.Domain');
var KanbanRecord = require('web.KanbanRecord');
var KanbanRenderer = require('web.KanbanRenderer');
var ListRenderer = require('web.ListRenderer');
-var Pager = require('web.Pager');
+const { ComponentWrapper, WidgetAdapterMixin } = require('web.OwlCompatibility');
var _t = core._t;
var _lt = core._lt;
@@ -963,7 +963,7 @@ var KanbanFieldMany2One = AbstractField.extend({
// X2Many widgets
//------------------------------------------------------------------------------
-var FieldX2Many = AbstractField.extend({
+var FieldX2Many = AbstractField.extend(WidgetAdapterMixin, {
tagName: 'div',
custom_events: _.extend({}, AbstractField.prototype.custom_events, {
add_record: '_onAddRecord',
@@ -980,6 +980,7 @@ var FieldX2Many = AbstractField.extend({
navigation_move: '_onNavigationMove',
save_optional_fields: '_onSaveOrLoadOptionalFields',
load_optional_fields: '_onSaveOrLoadOptionalFields',
+ pager_changed: '_onPagerChanged',
}),
// We need to trigger the reset on every changes to be aware of the parent changes
@@ -1006,6 +1007,21 @@ var FieldX2Many = AbstractField.extend({
this.isMany2Many = this.field.type === 'many2many' || this.attrs.widget === 'many2many';
this.activeActions = {};
this.recordParams = {fieldName: this.name, viewType: this.viewType};
+ // The limit is fixed so it cannot be changed by adding/removing lines in
+ // the widget. It will only change through a hard reload or when manually
+ // changing the pager (see _onPagerChanged).
+ this.pagingState = {
+ currentMinimum: this.value.offset + 1,
+ limit: this.value.limit,
+ size: this.value.count,
+ validate: () => {
+ // TODO: we should have some common method in the basic renderer...
+ return this.view.arch.tag === 'tree' ?
+ this.renderer.unselectRow() :
+ Promise.resolve();
+ },
+ withAccessKey: false,
+ };
var arch = this.view && this.view.arch;
if (arch) {
this.activeActions.create = arch.attrs.create ?
@@ -1024,8 +1040,21 @@ var FieldX2Many = AbstractField.extend({
/**
* @override
*/
- start: function () {
- return this._renderControlPanel().then(this._super.bind(this));
+ start: async function () {
+ const _super = this._super.bind(this);
+ if (this.view) {
+ this._renderButtons();
+ this._controlPanelWrapper = new ComponentWrapper(this, ControlPanelX2Many, {
+ cp_content: { $buttons: this.$buttons },
+ pager: this.pagingState,
+ });
+ await this._controlPanelWrapper.mount(this.el, { position: 'first-child' });
+ }
+ return _super(...arguments);
+ },
+ destroy: function () {
+ WidgetAdapterMixin.destroy.call(this);
+ this._super();
},
/**
* For the list renderer to properly work, it must know if it is in the DOM,
@@ -1033,6 +1062,7 @@ var FieldX2Many = AbstractField.extend({
*/
on_attach_callback: function () {
this.isInDOM = true;
+ WidgetAdapterMixin.on_attach_callback.call(this);
if (this.renderer) {
this.renderer.on_attach_callback();
}
@@ -1042,6 +1072,10 @@ var FieldX2Many = AbstractField.extend({
*/
on_detach_callback: function () {
this.isInDOM = false;
+ WidgetAdapterMixin.on_detach_callback.call(this);
+ if (this.renderer) {
+ this.renderer.on_detach_callback();
+ }
},
//--------------------------------------------------------------------------
@@ -1116,7 +1150,10 @@ var FieldX2Many = AbstractField.extend({
}
}
return this._super.apply(this, arguments).then(() => {
- this._updateControlPanel();
+ if (this.view) {
+ this._renderButtons();
+ this._updateControlPanel();
+ }
});
},
@@ -1249,8 +1286,8 @@ var FieldX2Many = AbstractField.extend({
addTrashIcon: this._hasTrashIcon(),
columnInvisibleFields: this.currentColInvisibleFields,
keepWidths: true,
- }).then(function () {
- self.pager.updateState({ size: self.value.count });
+ }).then(() => {
+ this._updateControlPanel({ size: this.value.count });
});
}
var arch = this.view.arch;
@@ -1303,59 +1340,6 @@ var FieldX2Many = AbstractField.extend({
}
},
/**
- * Instanciates a control panel with the appropriate buttons and a pager.
- * Prepends the control panel's $el to this widget's $el.
- *
- * @private
- * @returns {Promise}
- */
- _renderControlPanel: function () {
- if (!this.view) {
- return Promise.resolve();
- }
- var self = this;
- var defs = [];
- var controlPanelView = new ControlPanelView({
- template: 'X2ManyControlPanel',
- withSearchBar: false,
- });
- var cpDef = controlPanelView.getController(this).then(function (controlPanel) {
- self._controlPanel = controlPanel;
- return self._controlPanel.prependTo(self.$el);
- });
- this.pager = new Pager(this, this.value.count, this.value.offset + 1, this.value.limit, {
- single_page_hidden: true,
- withAccessKey: false,
- validate: function () {
- var isList = self.view.arch.tag === 'tree';
- // TODO: we should have some common method in the basic renderer...
- return isList ? self.renderer.unselectRow() : Promise.resolve();
- },
- });
- this.pager.on('pager_changed', this, function (new_state) {
- self.trigger_up('load', {
- id: self.value.id,
- limit: new_state.limit,
- offset: new_state.current_min - 1,
- on_success: function (value) {
- self.value = value;
- self._render();
- },
- });
- });
- this._renderButtons();
- defs.push(this.pager.appendTo($('<div>'))); // start the pager
- defs.push(cpDef);
- return Promise.all(defs).then(function () {
- self._controlPanel.updateContents({
- cp_content: {
- $buttons: self.$buttons,
- $pager: self.pager.$el,
- }
- });
- });
- },
- /**
* Renders the buttons and sets this.$buttons.
*
* @private
@@ -1395,8 +1379,8 @@ var FieldX2Many = AbstractField.extend({
} else {
self.renderer.setRowMode(recordID, 'readonly').then(resolve);
}
- }).then(function () {
- self.pager.updateState({ size: self.value.count });
+ }).then(async function () {
+ self._updateControlPanel({ size: self.value.count });
var newEval = self._evalColumnInvisibleFields();
if (!_.isEqual(self.currentColInvisibleFields, newEval)) {
self.currentColInvisibleFields = newEval;
@@ -1409,18 +1393,17 @@ var FieldX2Many = AbstractField.extend({
/**
* Re-renders buttons and updates the control panel. This method is called
* when the widget is reset, as the available buttons might have changed.
+ * The only mutable element in X2Many fields will be the pager.
*
* @private
*/
- _updateControlPanel: function () {
- if (this._controlPanel) {
- this._renderButtons();
- const params = {
- cp_content: {
- $buttons: this.$buttons,
- }
+ _updateControlPanel: function (pagingState) {
+ if (this._controlPanelWrapper) {
+ const newProps = {
+ cp_content: { $buttons: this.$buttons },
+ pager: Object.assign(this.pagingState, pagingState),
};
- this._controlPanel.updateContents(params, { clear: false });
+ return this._controlPanelWrapper.update(newProps);
}
},
/**
@@ -1577,6 +1560,30 @@ var FieldX2Many = AbstractField.extend({
// to implement
},
/**
+ * We re-render the pager immediately with the new event values to allow
+ * it to request another pager change while another one is still ongoing.
+ * @see field_manager_mixin for concurrency handling.
+ *
+ * @private
+ * @param {OdooEvent} ev
+ */
+ _onPagerChanged: function (ev) {
+ ev.stopPropagation();
+ const { currentMinimum, limit } = ev.data;
+ this._updateControlPanel({ currentMinimum, limit });
+ this.trigger_up('load', {
+ id: this.value.id,
+ limit,
+ offset: currentMinimum - 1,
+ on_success: value => {
+ this.value = value;
+ this.pagingState.limit = value.limit;
+ this.pagingState.size = value.count;
+ this._render();
+ },
+ });
+ },
+ /**
* Called when the renderer ask to save a line (the user tries to leave it)
* -> Nothing is to "save" here, the model was already notified of the line
* changes; if the row could be saved, we make the row readonly. Otherwise,
@@ -1777,7 +1784,7 @@ var FieldOne2Many = FieldX2Many.extend({
*/
reset: function (record, ev) {
var self = this;
- return this._super.apply(this, arguments).then(function () {
+ return this._super.apply(this, arguments).then(() => {
if (ev && ev.target === self && ev.data.changes && self.view.arch.tag === 'tree') {
if (ev.data.changes[self.name] && ev.data.changes[self.name].operation === 'CREATE') {
var index = 0;
@@ -1792,7 +1799,7 @@ var FieldOne2Many = FieldX2Many.extend({
// have 3 records, and we click on add, we will see the
// 4 records on the same page, but we do not want a
// pager.
- self.pager.updateState({ size: self.value.count - 1});
+ self._updateControlPanel({ size: self.value.count - 1 });
}
var newID = self.value.data[index].id;
self.renderer.editRecord(newID);
@@ -1832,7 +1839,7 @@ var FieldOne2Many = FieldX2Many.extend({
*/
_renderButtons: function () {
if (this.activeActions.create) {
- this._super.apply(this, arguments);
+ return this._super(...arguments);
}
},
/**