summaryrefslogtreecommitdiff
path: root/addons/web
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@odoo.com>2017-05-04 13:27:31 +0200
committerChristophe Matthieu <chm@odoo.com>2017-05-15 10:06:58 +0200
commit1c5ea99b7b82c2b6f28ad1a3dbffc1300fda6466 (patch)
tree806510fb1b7d26eae453ef1598253b7373f06b2a /addons/web
parentb57283619c4d1a711b2b071b9ec9c7008807a931 (diff)
[FIX] web: display a translation alert when saving the form view
In the form view, when the user saves a record (with a multilang instance), an alert is displayed to display all modified translatable fields.
Diffstat (limited to 'addons/web')
-rw-r--r--addons/web/doc/guidelines.rst1
-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
-rw-r--r--addons/web/static/tests/fields/basic_fields_tests.js8
-rw-r--r--addons/web/static/tests/views/form_tests.js33
10 files changed, 159 insertions, 36 deletions
diff --git a/addons/web/doc/guidelines.rst b/addons/web/doc/guidelines.rst
index 91e1e513a05..8721d372f5b 100644
--- a/addons/web/doc/guidelines.rst
+++ b/addons/web/doc/guidelines.rst
@@ -123,6 +123,7 @@ you should use:
*
* @override method from field manager mixin
* @param {string} id
+ * @returns {Deferred}
*/
_confirmSave: function (id) {
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>
diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js
index 8417e503676..2c1d0520748 100644
--- a/addons/web/static/tests/fields/basic_fields_tests.js
+++ b/addons/web/static/tests/fields/basic_fields_tests.js
@@ -662,7 +662,7 @@ QUnit.module('basic_fields', {
this.data.partner.fields.foo.translate = true;
- var multi_lang = _t.database.multi_lang;
+ var multiLang = _t.database.multi_lang;
_t.database.multi_lang = true;
var form = createView({
@@ -707,7 +707,7 @@ QUnit.module('basic_fields', {
assert.strictEqual($button.length, 0, "should not have a translate button in create mode");
form.destroy();
- _t.database.multi_lang = multi_lang;
+ _t.database.multi_lang = multiLang;
});
@@ -875,7 +875,7 @@ QUnit.module('basic_fields', {
this.data.partner.fields.txt.translate = true;
- var multi_lang = _t.database.multi_lang;
+ var multiLang = _t.database.multi_lang;
_t.database.multi_lang = true;
var form = createView({
@@ -920,7 +920,7 @@ QUnit.module('basic_fields', {
assert.strictEqual($button.length, 0, "should not have a translate button in create mode");
form.destroy();
- _t.database.multi_lang = multi_lang;
+ _t.database.multi_lang = multiLang;
});
QUnit.module('FieldBinary');
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index 52129f23f32..6754f9c2eb5 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -4377,5 +4377,38 @@ QUnit.module('Views', {
form.destroy();
});
+
+ QUnit.test('display translation alert', function (assert) {
+ assert.expect(1);
+
+ this.data.partner.fields.foo.translate = true;
+
+ var multi_lang = _t.database.multi_lang;
+ _t.database.multi_lang = true;
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<sheet>' +
+ '<group>' +
+ '<field name="foo"/>' +
+ '</group>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ form.$('input[name="foo"]').val("test").trigger("input");
+ form.$buttons.find('.o_form_button_save').click();
+
+ assert.strictEqual(form.$('.o_form_view > .alert > div').length, 1,"should have a translation alert");
+
+ form.destroy();
+
+ _t.database.multi_lang = multi_lang;
+ });
});
});