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/abstract_field.js14
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js33
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js32
3 files changed, 51 insertions, 28 deletions
diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js
index fa2f37a123f..9b484354544 100644
--- a/addons/web/static/src/js/fields/abstract_field.js
+++ b/addons/web/static/src/js/fields/abstract_field.js
@@ -65,12 +65,10 @@ var AbstractField = Widget.extend({
* @constructor
* @param {Widget} parent
* @param {string} name The field name defined in the model
- * @param {Object} record A record object (result of the get method of
+ * @param {Object} record A record object (result of the get method of
* a basic model)
* @param {Object} [options]
* @param {string} [options.mode=readonly] should be 'readonly' or 'edit'
- * @param {string} [options.standalone=false] this flag indicates that the
- * field does not have a controller to delegate to
*/
init: function (parent, name, record, options) {
this._super(parent);
@@ -160,10 +158,6 @@ var AbstractField = Widget.extend({
// calls to the format (resp. parse) function.
this.formatOptions = {};
this.parseOptions = {};
-
- // standalone is a flag indicating that the field does not have a
- // controller to delegate actions to
- this.standalone = options.standalone;
},
/**
* When a field widget is appended to the DOM, its start method is called,
@@ -379,6 +373,11 @@ var AbstractField = Widget.extend({
* @private
* @param {any} value
* @param {Object} [options]
+ * @param {boolean} [options.doNotSetDirty=false] if true, the basic model
+ * will not consider that this field is dirty, even though it was changed.
+ * Please do not use this flag unless you really need it. Our only use
+ * case is currently the pad widget, which does a _setValue in the
+ * renderEdit method.
* @param {boolean} [options.forceChange=false] if true, the change event will be
* triggered even if the new value is the same as the old one
* @returns {Deferred}
@@ -407,6 +406,7 @@ var AbstractField = Widget.extend({
dataPointID: this.dataPointID,
changes: changes,
viewType: this.viewType,
+ doNotSetDirty: options && options.doNotSetDirty,
onSuccess: def.resolve.bind(def),
onFailure: def.reject.bind(def),
});
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index 2f41f81f932..2de5a73802d 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -151,6 +151,9 @@ var DebouncedField = AbstractField.extend({
});
var InputField = DebouncedField.extend({
+ custom_events: _.extend({}, DebouncedField.prototype.custom_events, {
+ field_changed: '_onFieldChanged',
+ }),
events: _.extend({}, DebouncedField.prototype.events, {
'input': '_onInput',
'change': '_onChange',
@@ -168,6 +171,12 @@ var InputField = DebouncedField.extend({
if (this.mode === 'edit') {
this.tagName = 'input';
}
+ // 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;
},
//--------------------------------------------------------------------------
@@ -183,14 +192,21 @@ var InputField = DebouncedField.extend({
return this.$input || $();
},
/**
- * Do not re-render this field if it was the origin of the onchange call.
- * FIXME: make the onchange work on itself without disturbing the user typing
+ * 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.target === this) {
+ if (!event || event === this.lastChangeEvent) {
+ this.isDirty = false;
+ }
+ if (this.isDirty || (event && event.target === this)) {
return $.when();
} else {
return this._render();
@@ -266,6 +282,16 @@ var InputField = DebouncedField.extend({
this._doAction();
},
/**
+ * 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;
+ },
+ /**
* Called when the user is typing text -> By default this only calls a
* debounced method to notify the outside world of the changes.
* @see _doDebouncedAction
@@ -273,6 +299,7 @@ var InputField = DebouncedField.extend({
* @private
*/
_onInput: function () {
+ this.isDirty = true;
this._doDebouncedAction();
},
/**
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index 1935e5804dd..64049d8b1ec 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -223,25 +223,21 @@ var FieldMany2One = AbstractField.extend({
_quickCreate: function (name) {
var self = this;
var slowCreate = this._searchCreatePopup.bind(this, "form", false, this._createContext(name));
- var action = function () {
- return self._rpc({
- model: self.field.relation,
- method: 'name_create',
- args: [name],
- context: self.record.getContext(self.recordParams),
- }).then(function (result) {
- if (self.mode === "edit") {
- self.reinitialize({id: result[0], display_name: result[1]});
- }
- }, slowCreate);
- };
-
if (this.nodeOptions.quick_create) {
- if (this.standalone) {
- action();
- } else {
- this.trigger_up('mutexify', {action: action});
- }
+ this.trigger_up('mutexify', {
+ action: function () {
+ return self._rpc({
+ model: self.field.relation,
+ method: 'name_create',
+ args: [name],
+ context: self.record.getContext(self.recordParams),
+ }).then(function (result) {
+ if (self.mode === "edit") {
+ self.reinitialize({id: result[0], display_name: result[1]});
+ }
+ }, slowCreate);
+ },
+ });
} else {
slowCreate();
}