summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/fields/relational_fields.js
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-01-03 14:05:48 +0100
committerChristophe Simonis <chs@odoo.com>2018-01-03 14:05:48 +0100
commit55b810dc70cccb23144986d54fd28bb5f91f2b1b (patch)
treea83dda56dac7f02be26f6821dea5b2f1926ea7b0 /addons/web/static/src/js/fields/relational_fields.js
parent8bc7cebd9c19ae8f77378d115a8401d7b7de56b0 (diff)
parent726b91b9fbc994c6b2f2cb45e36d4c224497f11b (diff)
[MERGE] forward port branch saas-11.1 up to 726b91b9fbc
Diffstat (limited to 'addons/web/static/src/js/fields/relational_fields.js')
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js53
1 files changed, 48 insertions, 5 deletions
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index 52654c4ce3a..677663a4967 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -95,6 +95,7 @@ var FieldMany2One = AbstractField.extend({
template: 'FieldMany2One',
custom_events: _.extend({}, AbstractField.prototype.custom_events, {
'closed_unset': '_onDialogClosedUnset',
+ 'field_changed': '_onFieldChanged',
'quick_create': '_onQuickCreate',
'search_create_popup': '_onSearchCreatePopup',
}),
@@ -124,6 +125,12 @@ var FieldMany2One = AbstractField.extend({
// 'recordParams' is a dict of params used when calling functions
// 'getDomain' and 'getContext' on this.record
this.recordParams = {fieldName: this.name, viewType: this.viewType};
+ // We need to know if the widget is dirty (i.e. if the user has changed
+ // the value, and those changes haven't been acknowledged yet by the
+ // environment), to prevent erasing that new value on a reset (e.g.
+ // coming by an onchange on another field)
+ this.isDirty = false;
+ this.lastChangeEvent = undefined;
},
start: function () {
// booleean indicating that the content of the input isn't synchronized
@@ -151,9 +158,31 @@ var FieldMany2One = AbstractField.extend({
* TODO
*/
reinitialize: function (value) {
+ this.isDirty = false;
this.floating = false;
this._setValue(value);
},
+ /**
+ * Re-renders the widget if it isn't dirty. The widget is dirty if the user
+ * changed the value, and that change hasn't been acknowledged yet by the
+ * environment. For example, another field with an onchange has been updated
+ * and this field is updated before the onchange returns. Two '_setValue'
+ * are done (this is sequential), the first one returns and this widget is
+ * reset. However, it has pending changes, so we don't re-render.
+ *
+ * @override
+ */
+ reset: function (record, event) {
+ this._reset(record, event);
+ if (!event || event === this.lastChangeEvent) {
+ this.isDirty = false;
+ }
+ if (this.isDirty) {
+ return $.when();
+ } else {
+ return this._render();
+ }
+ },
//--------------------------------------------------------------------------
// Private
@@ -238,6 +267,16 @@ var FieldMany2One = AbstractField.extend({
return value.split('\n')[0];
},
/**
+ * Listens to events 'field_changed' to keep track of the last event that
+ * has been trigerred. This allows to detect that all changes have been
+ * acknowledged by the environment.
+ *
+ * @param {OdooEvent} event 'field_changed' event
+ */
+ _onFieldChanged: function (event) {
+ this.lastChangeEvent = event;
+ },
+ /**
* @private
* @param {string} name
* @returns {Deferred} resolved after the name_create or when the slowcreate
@@ -476,6 +515,7 @@ var FieldMany2One = AbstractField.extend({
* @private
*/
_onDialogClosedUnset: function () {
+ this.isDirty = false;
this.floating = false;
this._render();
},
@@ -544,6 +584,7 @@ var FieldMany2One = AbstractField.extend({
// confirmation that the many2one is not properly set.
return;
}
+ this.isDirty = true;
if (this.$input.val() === "") {
this.reinitialize(false);
} else if (this._getDisplayName(this.m2o_value) !== this.$input.val()) {
@@ -796,7 +837,7 @@ var FieldX2Many = AbstractField.extend({
this.currentColInvisibleFields = this._evalColumnInvisibleFields();
this.renderer = new ListRenderer(this, this.value, {
arch: arch,
- mode: this.mode,
+ editable: this.mode === 'edit' && arch.attrs.editable,
addCreateLine: !this.isReadonly && this.activeActions.create,
addTrashIcon: !this.isReadonly && this.activeActions.delete,
isMany2Many: this.isMany2Many,
@@ -1337,12 +1378,12 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({
throw _.str.sprintf(msg, this.field.string);
}
+ this.uploadedFiles = {};
this.uploadingFiles = [];
this.fileupload_id = _.uniqueId('oe_fileupload_temp');
$(window).on(this.fileupload_id, this._onFileLoaded.bind(this));
this.metadata = {};
- this._generatedMetadata();
},
destroy: function () {
@@ -1372,10 +1413,10 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({
_generatedMetadata: function () {
var self = this;
_.each(this.value.data, function (record) {
- // attachments are tagged `allowUnlink` because only new attachments
- // will be unlinked after deletion
+ // tagging `allowUnlink` ascertains if the attachment was user
+ // uploaded or was an existing or system generated attachment
self.metadata[record.id] = {
- allowUnlink: false,
+ allowUnlink: self.uploadedFiles[record.data.id] || false,
url: self._getFileUrl(record.data),
};
});
@@ -1387,6 +1428,7 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({
_render: function () {
// render the attachments ; as the attachments will changes after each
// _setValue, we put the rendering here to ensure they will be updated
+ this._generatedMetadata();
this.$('.oe_placeholder_files, .oe_attachments')
.replaceWith($(qweb.render('FieldBinaryFileUploader.files', {
widget: this,
@@ -1494,6 +1536,7 @@ var FieldMany2ManyBinaryMultiFiles = AbstractField.extend({
self.do_warn(_t('Uploading Error'), file.error);
} else {
attachment_ids.push(file.id);
+ self.uploadedFiles[file.id] = true;
}
});