summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js9
-rw-r--r--addons/web/static/src/js/views/basic/basic_controller.js42
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js34
-rw-r--r--addons/web/static/src/js/views/form/form_controller.js30
-rw-r--r--addons/web/static/src/js/views/form/form_renderer.js32
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_model.js4
-rw-r--r--addons/web/static/src/xml/base.xml2
7 files changed, 121 insertions, 32 deletions
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index b1b51e69e36..17cac8e86e5 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -56,14 +56,7 @@ var TranslatableFieldMixin = {
* @private
*/
_onTranslate: function () {
- this._rpc({
- route: '/web/dataset/call_button',
- params: {
- model: 'ir.translation',
- method: 'translate_fields',
- args: [this.model, this.res_id, this.name, this.record.getContext()],
- }
- }).then(this.do_action.bind(this));
+ this.trigger_up('translate', {fieldName: this.name, id: this.dataPointID});
},
};
diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js
index f1e71bcfd5a..4b38ac69403 100644
--- a/addons/web/static/src/js/views/basic/basic_controller.js
+++ b/addons/web/static/src/js/views/basic/basic_controller.js
@@ -19,7 +19,8 @@ var _t = core._t;
var BasicController = AbstractController.extend(FieldManagerMixin, {
custom_events: _.extend({}, AbstractController.prototype.custom_events, FieldManagerMixin.custom_events, {
reload: '_onReload',
- sidebar_data_asked: '_onSidebarDataAsked'
+ sidebar_data_asked: '_onSidebarDataAsked',
+ translate: '_onTranslate',
}),
/**
* @override
@@ -169,6 +170,8 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* @param {string} [recordID] - default to main recordID
* @param {Object} [options]
* @returns {Deferred}
+ * Resolved with the list of field names (whose value has been modified)
+ * Rejected if the record can't be saved
*/
saveRecord: function (recordID, options) {
// Some field widgets can't detect (all) their changes immediately or
@@ -367,6 +370,8 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* if true, the record will only be 'locally' saved: its changes
* will move from the _changes key to the data key
* @returns {Deferred}
+ * Resolved with the list of field names (whose value has been modified)
+ * Rejected if the record can't be saved
*/
_saveRecord: function (recordID, options) {
recordID = recordID || this.handle;
@@ -376,22 +381,24 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
savePoint: false,
});
- var def = $.Deferred();
// Check if the view is in a valid state for saving
// Note: it is the model's job to do nothing if there is nothing to save
if (this.canBeSaved(recordID)) {
- def = this.model.save(recordID, { // Save then leave edit mode
+ var self = this;
+ var def = this.model.save(recordID, { // Save then leave edit mode
reload: options.reload,
savePoint: options.savePoint,
});
- } else {
- def.reject(); // Cannot be saved, do nothing at all
- }
-
- if (options.stayInEdit) {
+ if (!options.stayInEdit) {
+ def = def.then(function (fieldNames) {
+ return self._confirmSave(recordID).then(function () {
+ return fieldNames;
+ });
+ });
+ }
return def;
} else {
- return def.then(this._confirmSave.bind(this, recordID));
+ return $.Deferred().reject(); // Cannot be saved
}
},
/**
@@ -498,6 +505,23 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
var sidebarEnv = this._getSidebarEnv();
event.data.callback(sidebarEnv);
},
+ /**
+ * open the translation view for the current field
+ *
+ * @private
+ * @param {OdooEvent} event
+ */
+ _onTranslate: function (event) {
+ var record = this.model.get(event.data.id, {raw: true});
+ this._rpc({
+ route: '/web/dataset/call_button',
+ params: {
+ model: 'ir.translation',
+ method: 'translate_fields',
+ args: [record.model, record.res_id, event.data.fieldName, record.getContext()],
+ }
+ }).then(this.do_action.bind(this));
+ },
});
return BasicController;
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js
index abb7242661e..ca042d63d69 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -708,6 +708,7 @@ var BasicModel = AbstractModel.extend({
* be 'locally' saved: its changes written in a _savePoint key that can
* be restored later by call discardChanges with option rollback to true
* @returns {Deferred}
+ * Resolved with the list of field names (whose value has been modified)
*/
save: function (record_id, options) {
var self = this;
@@ -723,7 +724,6 @@ var BasicModel = AbstractModel.extend({
rec._savePoint = _.extend({}, newValue);
}
});
- return $.when();
}
var shouldReload = 'reload' in options ? options.reload : true;
var method = self.isNew(record_id) ? 'create' : 'write';
@@ -742,10 +742,17 @@ var BasicModel = AbstractModel.extend({
});
}
+ var def = $.Deferred();
+ var changedFields = Object.keys(changes);
+
+ if (options.savePoint) {
+ return def.resolve(changedFields);
+ }
+
// in the case of a write, only perform the RPC if there are changes to save
- if (method === 'create' || Object.keys(changes).length) {
+ if (method === 'create' || changedFields.length) {
var args = method === 'write' ? [[record.data.id], changes] : [changes];
- return self._rpc({
+ self._rpc({
model: record.model,
method: method,
args: args,
@@ -759,23 +766,26 @@ var BasicModel = AbstractModel.extend({
record.count++;
}
- // Update the data directly or reload them
- var def;
- if (shouldReload) {
- def = self._fetchRecord(record);
- } else {
- _.extend(record.data, record._changes);
- }
+ var _changes = record._changes;
// Erase changes as they have been applied
record._changes = {};
record._isDirty = false;
- return def;
+ // Update the data directly or reload them
+ if (shouldReload) {
+ self._fetchRecord(record).then(function (record) {
+ def.resolve(changedFields);
+ });
+ } else {
+ _.extend(record.data, _changes);
+ def.resolve(changedFields);
+ }
});
} else {
- return $.when(record_id);
+ def.resolve(changedFields);
}
+ return def;
});
},
/**
diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js
index 31b858b1b01..99d21552be6 100644
--- a/addons/web/static/src/js/views/form/form_controller.js
+++ b/addons/web/static/src/js/views/form/form_controller.js
@@ -168,6 +168,35 @@ var FormController = BasicController.extend({
this._updateSidebar();
}
},
+ /**
+ * Show a warning message if the user modified a translated field. For each
+ * field, the notification provides a link to edit the field's translations.
+ *
+ * @override
+ */
+ saveRecord: function () {
+ var result = this._super.apply(this, arguments);
+ if (_t.database.multi_lang) {
+ var self = this;
+ result.then(function (changedFields) {
+ if (!changedFields.length) {
+ return changedFields;
+ }
+ var fields = self.renderer.state.fields;
+ var alertFields = [];
+ for (var k = 0; k < changedFields.length; k++) {
+ var field = fields[changedFields[k]];
+ if (field.translate) {
+ alertFields.push(field);
+ }
+ }
+ if (alertFields.length) {
+ self.renderer.displayTranslationAlert(alertFields);
+ }
+ });
+ }
+ return result;
+ },
//--------------------------------------------------------------------------
// Private
@@ -180,6 +209,7 @@ var FormController = BasicController.extend({
* @private
* @override method from field manager mixin
* @param {string} id
+ * @returns {Deferred}
*/
_confirmSave: function (id) {
if (id === this.handle) {
diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js
index 6dc4d262022..214b880d53d 100644
--- a/addons/web/static/src/js/views/form/form_renderer.js
+++ b/addons/web/static/src/js/views/form/form_renderer.js
@@ -10,6 +10,9 @@ var qweb = core.qweb;
var FormRenderer = BasicRenderer.extend({
className: "o_form_view",
+ events: _.extend({}, BasicRenderer.prototype.events, {
+ 'click .o_notification_box .oe_field_translate': '_onTranslate',
+ }),
/**
* @override
*/
@@ -49,6 +52,25 @@ var FormRenderer = BasicRenderer.extend({
return fieldNames;
},
/**
+ * Show a warning message if the user modified a translated field. For each
+ * field, the notification provides a link to edit the field's translations.
+ *
+ * @param {Object[]} alertFields: field list
+ */
+ displayTranslationAlert: function (alertFields) {
+ this.$('.o_notification_box').remove();
+ var $notification = $(qweb.render('notification-box', {type: 'info'}))
+ .append(qweb.render('translation-alert', {
+ fields: alertFields,
+ lang: _t.database.parameters.name
+ }));
+ if (this.$('.o_form_statusbar').length) {
+ this.$('.o_form_statusbar').after($notification);
+ } else {
+ this.$el.prepend($notification);
+ }
+ },
+ /**
* @see BasicRenderer.confirmChange
*
* We need to reapply the idForLabel postprocessing since some widgets may
@@ -771,6 +793,16 @@ var FormRenderer = BasicRenderer.extend({
this._activatePreviousFieldWidget(this.state, index);
}
},
+ /**
+ * open the translation view for the current field
+ *
+ * @private
+ * @param {MouseEvent} ev
+ */
+ _onTranslate: function (event) {
+ event.preventDefault();
+ this.trigger_up('translate', {fieldName: event.target.name, id: this.state.id});
+ },
});
return FormRenderer;
diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js
index 9e5e0fc1267..bdf58858b02 100644
--- a/addons/web/static/src/js/views/kanban/kanban_model.js
+++ b/addons/web/static/src/js/views/kanban/kanban_model.js
@@ -127,7 +127,7 @@ var KanbanModel = BasicModel.extend({
}
return this.notifyChanges(recordID, changes).then(function () {
return self.save(recordID);
- }).then(function (result) {
+ }).then(function () {
// Remove record from its current group
var old_group;
for (var i = 0; i < parent.count; i++) {
@@ -140,7 +140,7 @@ var KanbanModel = BasicModel.extend({
}
}
// Add record to its new group
- new_group.data.push(result.id);
+ new_group.data.push(recordID);
new_group.count++;
return [old_group.id, new_group.id];
});
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 96a0b809441..b9b7caeea7d 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -1219,7 +1219,7 @@
</t>
<t t-name="notification-box">
- <div t-att-class="'alert alert-dismissible alert-' + type" role="alert">
+ <div t-attf-class="o_notification_box alert alert-dismissible alert-{{type}}" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true" class="fa fa-times"></span>
</button>