[FIX] mail: re-bind handlers on chatter buttons

When a user opens a record in a form view, the chatter is
displayed. Then, if he clicks on 'Create', the chatter is removed
from the DOM (there is no chatter in create mode). After saving
the newly created record, the chatter is displayed again, but the
same widget's instance is kept.

However, when being removed from the DOM, the event handlers bound
on elements of the chatter (e.g. 'New Message', 'Log a Note'...
buttons) are automatically unbound.

So before this rev., the buttons didn't work anymore once the form
view had switched to create mode. In this commit, we detach the
chatter's $el before updating the view, so that its handlers aren't
unbound when the old content is replaced by the new one.
This commit is contained in:
Aaron Bohy
2017-04-25 08:07:17 +02:00
parent f5bfa3d3b6
commit 764127357c
3 changed files with 71 additions and 29 deletions
@@ -70,6 +70,22 @@ FormRenderer.include({
return this._super.apply(this, arguments);
}
},
/**
* Detaches the chatter before updating the $el. This is important because
* if the view is now in create mode (edit mode with no res_id), the chatter
* will be removed from the DOM, and its handlers will be unbound. By
* detaching it beforehand, we ensure to keep its handlers alive so that if
* it is re-appended later, everything will still work properly.
*
* @override
* @private
*/
_updateView: function () {
if (this.chatter) {
this.chatter.$el.detach();
}
return this._super.apply(this, arguments);
},
});
});
+21 -8
View File
@@ -155,7 +155,7 @@ QUnit.test('basic rendering', function (assert) {
});
QUnit.test('chatter is not rendered in mode === create', function (assert) {
assert.expect(2);
assert.expect(4);
var form = createView({
View: FormView,
@@ -171,11 +171,8 @@ QUnit.test('chatter is not rendered in mode === create', function (assert) {
'</form>',
res_id: 2,
mockRPC: function (route, args) {
if (route === '/mail/read_followers') {
return $.when({
followers: [],
subtypes: [],
});
if (route === "/web/dataset/call_kw/partner/message_get_suggested_recipients") {
return $.when({2: []});
}
return this._super(route, args);
},
@@ -191,9 +188,25 @@ QUnit.test('chatter is not rendered in mode === create', function (assert) {
},
});
assert.ok(form.$('.o_chatter').length, "there should be a chatter widget");
assert.strictEqual(form.$('.o_chatter').length, 1,
"chatter should be displayed");
form.$buttons.find('.o_form_button_create').click();
assert.ok(!form.$('.o_chatter').length, "there should not be a chatter widget");
assert.strictEqual(form.$('.o_chatter').length, 0,
"chatter should not be displayed");
form.$('.o_form_input').val('coucou').trigger('input');
form.$buttons.find('.o_form_button_save').click();
assert.strictEqual(form.$('.o_chatter').length, 1,
"chatter should be displayed");
// check if chatter buttons still work
form.$('.o_chatter_button_new_message').click();
assert.strictEqual(form.$('.o_chat_composer:visible').length, 1,
"chatter should be opened");
form.destroy();
});
@@ -692,31 +692,44 @@ var FormRenderer = BasicRenderer.extend({
delete this.defs;
return $.when.apply($, defs).then(function () {
self.$el.html($form.contents());
self._updateView($form.contents());
});
},
/**
* Updates the form's $el with new content.
*
* @private
* @see _renderView
* @param {JQuery} $newContent
*/
_updateView: function ($newContent) {
var self = this;
// Necessary to allow all sub widgets to use their dimensions in
// layout related activities, such as autoresize on fieldtexts
core.bus.trigger('DOM_updated');
// Set the new content of the form view, and toggle classnames
this.$el.html($newContent);
this.$el.toggleClass('o_form_nosheet', !this.has_sheet);
this.$el.toggleClass('o_form_editable', this.mode === 'edit');
this.$el.toggleClass('o_form_readonly', this.mode === 'readonly');
self.$el.toggleClass('o_form_nosheet', !self.has_sheet);
self.$el.toggleClass('o_form_editable', self.mode === 'edit');
self.$el.toggleClass('o_form_readonly', self.mode === 'readonly');
// Attach the tooltips on the fields' label
var focusWidget = self.defaultFocusField;
_.each(self.allFieldWidgets[self.state.id], function (widget) {
if (!focusWidget) {
focusWidget = widget;
}
if (core.debug || widget.attrs.help || widget.field.help) {
var idForLabel = self.idsForLabels[widget.name];
var $label = idForLabel ? self.$('label[for=' + idForLabel + ']') : $();
self._addFieldTooltip(widget, $label);
}
});
if (focusWidget) {
focusWidget.activate(true);
// Necessary to allow all sub widgets to use their dimensions in
// layout related activities, such as autoresize on fieldtexts
core.bus.trigger('DOM_updated');
// Attach the tooltips on the fields' label
var focusWidget = this.defaultFocusField;
_.each(this.allFieldWidgets[this.state.id], function (widget) {
if (!focusWidget) {
focusWidget = widget;
}
if (core.debug || widget.attrs.help || widget.field.help) {
var idForLabel = self.idsForLabels[widget.name];
var $label = idForLabel ? self.$('label[for=' + idForLabel + ']') : $();
self._addFieldTooltip(widget, $label);
}
});
if (focusWidget) {
focusWidget.activate(true);
}
},
//--------------------------------------------------------------------------