summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views/field_manager_mixin.js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/web/static/src/js/views/field_manager_mixin.js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/web/static/src/js/views/field_manager_mixin.js')
-rw-r--r--addons/web/static/src/js/views/field_manager_mixin.js166
1 files changed, 166 insertions, 0 deletions
diff --git a/addons/web/static/src/js/views/field_manager_mixin.js b/addons/web/static/src/js/views/field_manager_mixin.js
new file mode 100644
index 00000000..aab8dd14
--- /dev/null
+++ b/addons/web/static/src/js/views/field_manager_mixin.js
@@ -0,0 +1,166 @@
+odoo.define('web.FieldManagerMixin', function (require) {
+"use strict";
+
+/**
+ * The FieldManagerMixin is a mixin, designed to do the plumbing between field
+ * widgets and a basicmodel. Field widgets can be used outside of a view. In
+ * that case, someone needs to listen to events bubbling up from the widgets and
+ * calling the correct methods on the model. This is the field_manager's job.
+ */
+
+var BasicModel = require('web.BasicModel');
+var concurrency = require('web.concurrency');
+
+var FieldManagerMixin = {
+ custom_events: {
+ field_changed: '_onFieldChanged',
+ load: '_onLoad',
+ mutexify: '_onMutexify',
+ },
+ /**
+ * A FieldManagerMixin can be initialized with an instance of a basicModel.
+ * If not, it will simply uses its own.
+ *
+ * @param {BasicModel} [model]
+ */
+ init: function (model) {
+ this.model = model || new BasicModel(this);
+ this.mutex = new concurrency.Mutex();
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Apply changes by notifying the basic model, then saving the data if
+ * necessary, and finally, confirming the changes to the UI.
+ *
+ * @todo find a way to remove ugly 3rd argument...
+ *
+ * @param {string} dataPointID
+ * @param {Object} changes
+ * @param {OdooEvent} event
+ * @returns {Promise} resolves when the change has been done, and the UI
+ * updated
+ */
+ _applyChanges: function (dataPointID, changes, event) {
+ var self = this;
+ var options = _.pick(event.data, 'context', 'doNotSetDirty', 'notifyChange', 'viewType', 'allowWarning');
+ return this.model.notifyChanges(dataPointID, changes, options)
+ .then(function (result) {
+ if (event.data.force_save) {
+ return self.model.save(dataPointID).then(function () {
+ return self._confirmSave(dataPointID);
+ }).guardedCatch(function () {
+ return self._rejectSave(dataPointID);
+ });
+ } else if (options.notifyChange !== false) {
+ return self._confirmChange(dataPointID, result, event);
+ }
+ });
+ },
+ /**
+ * This method will be called whenever a field value has changed (and has
+ * been confirmed by the model).
+ *
+ * @abstract
+ * @param {string} id basicModel Id for the changed record
+ * @param {string[]} fields the fields (names) that have been changed
+ * @param {OdooEvent} event the event that triggered the change
+ * @returns {Promise}
+ */
+ _confirmChange: function (id, fields, event) {
+ return Promise.resolve();
+ },
+ /**
+ * This method will be called whenever a save has been triggered by a change
+ * in some controlled field value. For example, when a priority widget is
+ * being changed in a readonly form.
+ *
+ * @see _onFieldChanged
+ * @abstract
+ * @param {string} id The basicModel ID for the saved record
+ * @returns {Promise}
+ */
+ _confirmSave: function (id) {
+ return Promise.resolve();
+ },
+ /**
+ * This method will be called whenever a save has been triggered by a change
+ * and has failed. For example, when a statusbar button is clicked in a
+ * readonly form view.
+ *
+ * @abstract
+ * @private
+ * @param {string} id The basicModel ID for the saved record
+ * @returns {Deferred}
+ */
+ _rejectSave: function (id) {
+ return Promise.resolve();
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * This is the main job of the FMM: deciding what to do when a controlled
+ * field changes. Most of the time, it notifies the model that a change
+ * just occurred, then confirm the change.
+ *
+ * @param {OdooEvent} event
+ */
+ _onFieldChanged: function (event) {
+ // in case of field changed in relational record (e.g. in the form view
+ // of a one2many subrecord), the field_changed event must be stopped as
+ // soon as is it handled by a field_manager (i.e. the one of the
+ // subrecord's form view), otherwise it bubbles up to the main form view
+ // but its model doesn't have any data related to the given dataPointID
+ event.stopPropagation();
+ return this._applyChanges(event.data.dataPointID, event.data.changes, event)
+ .then(event.data.onSuccess || function () {})
+ .guardedCatch(event.data.onFailure || function () {});
+ },
+ /**
+ * Some widgets need to trigger a reload of their data. For example, a
+ * one2many with a pager needs to be able to fetch the next page. To do
+ * that, it can trigger a load event. This will then ask the model to
+ * actually reload the data, then call the on_success callback.
+ *
+ * @param {OdooEvent} event
+ * @param {number} [event.data.limit]
+ * @param {number} [event.data.offset]
+ * @param {function} [event.data.on_success] callback
+ */
+ _onLoad: function (event) {
+ var self = this;
+ event.stopPropagation(); // prevent other field managers from handling this request
+ var data = event.data;
+ if (!data.on_success) { return; }
+ var params = {};
+ if ('limit' in data) {
+ params.limit = data.limit;
+ }
+ if ('offset' in data) {
+ params.offset = data.offset;
+ }
+ this.mutex.exec(function () {
+ return self.model.reload(data.id, params).then(function (db_id) {
+ data.on_success(self.model.get(db_id));
+ });
+ });
+ },
+ /**
+ * @private
+ * @param {OdooEvent} ev
+ * @param {function} ev.data.action the function to execute in the mutex
+ */
+ _onMutexify: function (ev) {
+ ev.stopPropagation(); // prevent other field managers from handling this request
+ this.mutex.exec(ev.data.action);
+ },
+};
+
+return FieldManagerMixin;
+});